OSDN Git Service

* jcf-io.c (find_class): Use saw_java_source to determine when to
[pf3gnuchains/gcc-fork.git] / gcc / java / jcf-io.c
1 /* Utility routines for finding and reading Java(TM) .class files.
2    Copyright (C) 1996, 1998  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 <sys/stat.h>
30 #include <sys/wait.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)
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 (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 int
93 DEFUN(open_in_zip, (jcf, zipfile, zipmember),
94       JCF *jcf AND const char *zipfile AND const char *zipmember
95       AND int is_system)
96 {
97   struct ZipFileCache* zipf;
98   ZipDirectory *zipd;
99   int i, len;
100   for (zipf = SeenZipFiles; ; zipf = zipf->next)
101     {
102       if (zipf == NULL)
103         {
104           char magic [4];
105           int fd = open (zipfile, O_RDONLY | O_BINARY);
106           jcf_dependency_add_file (zipfile, is_system);
107           if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
108             return -1;
109           lseek (fd, 0L, SEEK_SET);
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           zipf->z.fd = fd;
116           if (fd == -1)
117             {
118               /* A missing zip file is not considered an error. */
119               zipf->z.count = 0;
120               zipf->z.dir_size = 0;
121               zipf->z.central_directory = NULL;
122               return -1;
123             }
124           else
125             {
126               if (read_zip_archive (&zipf->z) != 0)
127                 return -2; /* This however should be an error - FIXME */
128             }
129           break;
130         }
131       if (strcmp (zipf->name, zipfile) == 0)
132         break;
133     }
134
135   if (!zipmember)
136     return 0;
137
138   len = strlen (zipmember);
139   
140   zipd = (struct ZipDirectory*) zipf->z.central_directory;
141   for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd))
142     {
143       if (len == zipd->filename_length &&
144           strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
145         {
146           JCF_ZERO (jcf);
147           jcf->buffer = ALLOC (zipd->size);
148           jcf->buffer_end = jcf->buffer + zipd->size;
149           jcf->read_ptr = jcf->buffer;
150           jcf->read_end = jcf->buffer_end;
151           jcf->filbuf = jcf_unexpected_eof;
152           jcf->filename = strdup (zipfile);
153           jcf->classname = strdup (zipmember);
154           jcf->zipd = (void *)zipd;
155           if (lseek (zipf->z.fd, zipd->filestart, 0) < 0
156               || read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size)
157             return -2;
158           return 0;
159         }
160     }
161   return -1;
162 }
163
164 #if JCF_USE_STDIO
165 char*
166 DEFUN(open_class, (filename, jcf, stream, dep_name),
167       char *filename AND JCF *jcf AND FILE* stream AND char *dep_name)
168 {
169   if (jcf)
170     {
171       if (dep_name != NULL)
172         jcf_dependency_add_file (dep_name, 0);
173       JCF_ZERO (jcf);
174       jcf->buffer = NULL;
175       jcf->buffer_end = NULL;
176       jcf->read_ptr = NULL;
177       jcf->read_end = NULL;
178       jcf->read_state = stream;
179       jcf->filbuf = jcf_filbuf_from_stdio;
180     }
181   else
182     fclose (stream);
183   return filename;
184 }
185 #else
186 char*
187 DEFUN(open_class, (filename, jcf, fd, dep_name),
188       char *filename AND JCF *jcf AND int fd AND char *dep_name)
189 {
190   if (jcf)
191     {
192       struct stat stat_buf;
193       if (fstat (fd, &stat_buf) != 0
194           || ! S_ISREG (stat_buf.st_mode))
195         {
196           perror ("Could not figure length of .class file");
197           return NULL;
198         }
199       if (dep_name != NULL)
200         jcf_dependency_add_file (dep_name, 0);
201       JCF_ZERO (jcf);
202       jcf->buffer = ALLOC (stat_buf.st_size);
203       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
204       jcf->read_ptr = jcf->buffer;
205       jcf->read_end = jcf->buffer_end;
206       jcf->read_state = NULL;
207       jcf->filename = filename;
208       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
209         {
210           perror ("Failed to read .class file");
211           return NULL;
212         }
213       close (fd);
214       jcf->filbuf = jcf_unexpected_eof;
215     }
216   else
217     close (fd);
218   return filename;
219 }
220 #endif
221
222
223 char *
224 DEFUN(find_classfile, (filename, jcf, dep_name),
225       char *filename AND JCF *jcf AND char *dep_name)
226 {
227 #if JCF_USE_STDIO
228   FILE *stream = fopen (filename, "rb");
229   if (stream == NULL)
230     return NULL;
231   return open_class (arg, jcf, stream, dep_name);
232 #else
233   int fd = open (filename, O_RDONLY | O_BINARY);
234   if (fd < 0)
235     return NULL;
236   return open_class (filename, jcf, fd, dep_name);
237 #endif
238 }
239
240 /* Returns a freshly malloc'd string with the fully qualified pathname
241    of the .class file for the class CLASSNAME.  Returns NULL on
242    failure.  If JCF != NULL, it is suitably initialized.  With
243    DO_CLASS_FILE set to 1, search a .class/.java file named after
244    CLASSNAME, otherwise, search a ZIP directory entry named after
245    CLASSNAME.  */
246
247 char *
248 DEFUN(find_class, (classname, classname_length, jcf, do_class_file),
249       const char *classname AND int classname_length AND JCF *jcf AND int do_class_file)
250
251 {
252 #if JCF_USE_STDIO
253   FILE *stream;
254 #else
255   int fd;
256 #endif
257   int i, k, java, class;
258   struct stat java_buf, class_buf;
259   char *dep_file;
260   void *entry, *java_entry;
261   char *java_buffer;
262
263   /* Allocate and zero out the buffer, since we don't explicitly put a
264      null pointer when we're copying it below.  */
265   int buflen = jcf_path_max_len () + classname_length + 10;
266   char *buffer = (char *) ALLOC (buflen);
267   bzero (buffer, buflen);
268
269   java_buffer = (char *) alloca (buflen);
270
271   jcf->java_source = jcf->outofsynch = 0;
272
273   for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
274     {
275       int dir_len;
276
277       strcpy (buffer, jcf_path_name (entry));
278       i = strlen (buffer);
279
280       dir_len = i - 1;
281
282       for (k = 0; k < classname_length; k++, i++)
283         {
284           char ch = classname[k];
285           buffer[i] = ch == '.' ? '/' : ch;
286         }
287       if (do_class_file)
288         strcpy (buffer+i, ".class");
289
290       if (jcf_path_is_zipfile (entry))
291         {
292           int err_code;
293           JCF _jcf;
294           if (!do_class_file)
295             strcpy (buffer+i, "/");
296           buffer[dir_len] = '\0';
297           if (do_class_file)
298             SOURCE_FRONTEND_DEBUG 
299               (("Trying [...%s]:%s", 
300                 &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], 
301                 buffer+dir_len+1));
302           if (jcf == NULL)
303             jcf = &_jcf;
304           err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
305                                   jcf_path_is_system (entry));
306           if (err_code == 0)
307             {
308               if (!do_class_file)
309                 jcf->seen_in_zip = 1;
310               else
311                 {
312                   buffer[dir_len] = '(';
313                   strcpy (buffer+i, ".class)");
314                 }
315               if (jcf == &_jcf)
316                 JCF_FINISH (jcf);
317               return buffer;
318             }
319           else
320             continue;
321         }
322
323       /* If we do directories, do them here */
324       if (!do_class_file)
325         {
326           struct stat dir_buff;
327           int dir;
328           buffer[i] = '\0';     /* Was previously unterminated here. */
329           if (!(dir = stat (buffer, &dir_buff)))
330             {
331               jcf->seen_in_zip = 0;
332               goto found;
333             }
334         }
335
336       class = stat (buffer, &class_buf);
337       /* This is a little odd: if we didn't find the class file, we
338          can just skip to the next iteration.  However, if this is the
339          last iteration, then we want to search for the .java file as
340          well.  It was a little easier to implement this with two
341          loops, as opposed to checking for each type of file each time
342          through the loop.  */
343       if (class && jcf_path_next (entry))
344         continue;
345
346       /* Check for out of synch .class/.java files.  */
347       java = 1;
348       for (java_entry = jcf_path_start ();
349            java && java_entry != NULL;
350            java_entry = jcf_path_next (java_entry))
351         {
352           int m, l;
353           extern int saw_java_source; /* FIXME: temporary.   */
354
355           if (jcf_path_is_zipfile (java_entry))
356             continue;
357
358           /* Compute name of .java file.  */
359           strcpy (java_buffer, jcf_path_name (java_entry));
360           l = strlen (java_buffer);
361           for (m = 0; m < classname_length; ++m)
362             {
363               java_buffer[m + l] = (classname[m] == '.'
364                                     ? '/'
365                                     : classname[m]);
366             }
367           strcpy (java_buffer + m + l, ".java");
368
369           /* FIXME: until the `.java' parser is fully working, we only
370              look for a .java file when one was mentioned on the
371              command line.  This lets us test the .java parser fairly
372              easily, without compromising our ability to use the
373              .class parser without fear.  */
374           if (saw_java_source)
375             java = stat (java_buffer, &java_buf);
376         }
377
378       if (! java && ! class && java_buf.st_mtime >= class_buf.st_mtime)
379         jcf->outofsynch = 1;
380
381       if (! java)
382         dep_file = java_buffer;
383       else
384         dep_file = buffer;
385 #if JCF_USE_STDIO
386       if (!class)
387         {
388           SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
389           stream = fopen (buffer, "rb");
390           if (stream)
391             goto found;
392         }
393       /* Give .java a try, if necessary */
394       if (!java)
395         {
396           strcpy (buffer, java_buffer);
397           SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
398           stream = fopen (buffer, "r");
399           if (stream)
400             {
401               jcf->java_source = 1;
402               goto found;
403             }
404         }
405 #else
406       if (!class)
407         {
408           SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
409           fd = open (buffer, O_RDONLY | O_BINARY);
410           if (fd >= 0)
411             goto found;
412         }
413       /* Give .java a try, if necessary */
414       if (!java)
415         {
416           strcpy (buffer, java_buffer);
417           SOURCE_FRONTEND_DEBUG (("Trying %s", buffer));
418           fd = open (buffer, O_RDONLY);
419           if (fd >= 0)
420             {
421               jcf->java_source = 1;
422               goto found;
423             }
424         }
425 #endif
426     }
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)
437     {
438       JCF_ZERO (jcf);           /* JCF_FINISH relies on this */
439       jcf->java_source = 1;
440       jcf->filename = (char *) strdup (buffer);
441       close (fd);               /* We use STDIO for source file */
442     }
443   else if (do_class_file)
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 = (char *) strdup (classname);
448   return buffer;
449 #endif
450 }
451
452 void
453 DEFUN(jcf_print_char, (stream, ch),
454       FILE *stream AND int ch)
455 {
456   switch (ch)
457     {
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);
479     }
480 }
481
482 /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
483
484 void
485 DEFUN(jcf_print_utf8, (stream, str, length),
486       FILE *stream AND register unsigned char *str AND int length)
487 {
488   unsigned char* limit = str + length;
489   while (str < limit)
490     {
491       int ch = UTF8_GET (str, limit);
492       if (ch < 0)
493         {
494           fprintf (stream, "\\<invalid>");
495           return;
496         }
497       jcf_print_char (stream, ch);
498     }
499 }
500
501 /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
502
503 void
504 DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
505       FILE *stream AND unsigned char *str AND int length
506       AND int in_char AND int out_char)
507 {
508
509   int i;/* FIXME - actually handle Unicode! */
510   for (i = 0; i < length; i++)
511     {
512       int ch = str[i];
513       jcf_print_char (stream, ch == in_char ? out_char : ch);
514     }
515 }
516
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. */
520
521 int
522 DEFUN(verify_constant_pool, (jcf),
523       JCF *jcf)
524 {
525   int i, n;
526   for (i = 1; i < JPOOL_SIZE (jcf); i++)
527     {
528       switch (JPOOL_TAG (jcf, i))
529         {
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;
566         }
567     }
568   return 0;
569 }
570
571 void
572 DEFUN(format_uint, (buffer, value, base),
573       char *buffer AND uint64 value AND int base)
574 {
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;
580
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);
589
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;
594 }
595
596 void
597 DEFUN(format_int, (buffer, value, base),
598       char *buffer AND jlong value AND int base)
599 {
600   uint64 abs_value;
601   if (value < 0)
602     {
603       abs_value = -(uint64)value;
604       *buffer++ = '-';
605     }
606   else
607     abs_value = (uint64) value;
608   format_uint (buffer, abs_value, base);
609 }