]>
Commit | Line | Data |
---|---|---|
e04a16fb | 1 | /* Utility routines for finding and reading Java(TM) .class files. |
a15135c9 | 2 | Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc. |
e04a16fb AG |
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 | ||
1f43f4b4 JL |
25 | #include "config.h" |
26 | #include "system.h" | |
4977bab6 ZW |
27 | #include "coretypes.h" |
28 | #include "tm.h" | |
e04a16fb | 29 | |
e04a16fb | 30 | #include "jcf.h" |
4bcde32e | 31 | #include "tree.h" |
ee07f4f4 | 32 | #include "toplev.h" |
4bcde32e | 33 | #include "java-tree.h" |
a15135c9 MM |
34 | #include "hashtab.h" |
35 | #if JCF_USE_SCANDIR | |
36 | #include <dirent.h> | |
37 | #include <fnmatch.h> | |
38 | #endif | |
e04a16fb | 39 | |
3ca8c9ae AG |
40 | #include "zlib.h" |
41 | ||
e04a16fb AG |
42 | /* DOS brain-damage */ |
43 | #ifndef O_BINARY | |
44 | #define O_BINARY 0 /* MS-DOS brain-damage */ | |
45 | #endif | |
46 | ||
e04a16fb AG |
47 | int |
48 | DEFUN(jcf_unexpected_eof, (jcf, count), | |
b4b63e32 | 49 | JCF *jcf AND int count ATTRIBUTE_UNUSED) |
e04a16fb AG |
50 | { |
51 | if (jcf->filename) | |
52 | fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename); | |
53 | else | |
54 | fprintf (stderr, "Premature end of .class file <stdin>.\n"); | |
55 | exit (-1); | |
56 | } | |
57 | ||
58 | void | |
59 | DEFUN(jcf_trim_old_input, (jcf), | |
60 | JCF *jcf) | |
61 | { | |
62 | int count = jcf->read_ptr - jcf->buffer; | |
63 | if (count > 0) | |
64 | { | |
65 | memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr); | |
66 | jcf->read_ptr -= count; | |
67 | jcf->read_end -= count; | |
68 | } | |
69 | } | |
70 | ||
71 | int | |
72 | DEFUN(jcf_filbuf_from_stdio, (jcf, count), | |
73 | JCF *jcf AND int count) | |
74 | { | |
75 | FILE *file = (FILE*) (jcf->read_state); | |
76 | if (count > jcf->buffer_end - jcf->read_ptr) | |
77 | { | |
78 | JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer; | |
79 | JCF_u4 old_read_end = jcf->read_end - jcf->buffer; | |
80 | JCF_u4 old_size = jcf->buffer_end - jcf->buffer; | |
81 | JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count; | |
82 | unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size) | |
83 | : REALLOC (jcf->buffer, new_size); | |
84 | jcf->buffer = new_buffer; | |
85 | jcf->buffer_end = new_buffer + new_size; | |
86 | jcf->read_ptr = new_buffer + old_read_ptr; | |
87 | jcf->read_end = new_buffer + old_read_end; | |
88 | } | |
89 | count -= jcf->read_end - jcf->read_ptr; | |
90 | if (count <= 0) | |
91 | return 0; | |
d4476be2 | 92 | if ((int) fread (jcf->read_end, 1, count, file) != count) |
e04a16fb AG |
93 | jcf_unexpected_eof (jcf, count); |
94 | jcf->read_end += count; | |
95 | return 0; | |
96 | } | |
97 | ||
e04a16fb AG |
98 | #include "zipfile.h" |
99 | ||
a4796c80 | 100 | struct ZipFile *SeenZipFiles = NULL; |
e04a16fb | 101 | |
502f194f PB |
102 | /* Open a zip file with the given name, and cache directory and file |
103 | descriptor. If the file is missing, treat it as an empty archive. | |
104 | Return NULL if the .zip file is malformed. | |
105 | */ | |
106 | ||
107 | ZipFile * | |
108 | DEFUN(opendir_in_zip, (zipfile, is_system), | |
109 | const char *zipfile AND int is_system) | |
110 | { | |
a4796c80 | 111 | struct ZipFile* zipf; |
502f194f PB |
112 | char magic [4]; |
113 | int fd; | |
114 | for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next) | |
115 | { | |
116 | if (strcmp (zipf->name, zipfile) == 0) | |
a4796c80 | 117 | return zipf; |
502f194f PB |
118 | } |
119 | ||
a4796c80 | 120 | zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1); |
502f194f PB |
121 | zipf->next = SeenZipFiles; |
122 | zipf->name = (char*)(zipf+1); | |
123 | strcpy (zipf->name, zipfile); | |
124 | SeenZipFiles = zipf; | |
125 | fd = open (zipfile, O_RDONLY | O_BINARY); | |
a4796c80 | 126 | zipf->fd = fd; |
502f194f PB |
127 | if (fd < 0) |
128 | { | |
129 | /* A missing zip file is not considered an error. | |
130 | We may want to re-consider that. FIXME. */ | |
a4796c80 PB |
131 | zipf->count = 0; |
132 | zipf->dir_size = 0; | |
133 | zipf->central_directory = NULL; | |
502f194f PB |
134 | } |
135 | else | |
136 | { | |
137 | jcf_dependency_add_file (zipfile, is_system); | |
138 | if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC) | |
139 | return NULL; | |
140 | lseek (fd, 0L, SEEK_SET); | |
a4796c80 | 141 | if (read_zip_archive (zipf) != 0) |
502f194f PB |
142 | return NULL; |
143 | } | |
a4796c80 | 144 | return zipf; |
502f194f PB |
145 | } |
146 | ||
147 | /* Returns: | |
148 | 0: OK - zipmember found. | |
149 | -1: Not found. | |
150 | -2: Malformed archive. | |
151 | */ | |
152 | ||
e04a16fb | 153 | int |
502f194f | 154 | DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system), |
8603f9c5 TT |
155 | JCF *jcf AND const char *zipfile AND const char *zipmember |
156 | AND int is_system) | |
e04a16fb | 157 | { |
e04a16fb AG |
158 | ZipDirectory *zipd; |
159 | int i, len; | |
502f194f PB |
160 | ZipFile *zipf = opendir_in_zip (zipfile, is_system); |
161 | ||
162 | if (zipf == NULL) | |
163 | return -2; | |
e04a16fb AG |
164 | |
165 | if (!zipmember) | |
166 | return 0; | |
167 | ||
168 | len = strlen (zipmember); | |
169 | ||
502f194f PB |
170 | zipd = (struct ZipDirectory*) zipf->central_directory; |
171 | for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd)) | |
e04a16fb AG |
172 | { |
173 | if (len == zipd->filename_length && | |
174 | strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0) | |
175 | { | |
176 | JCF_ZERO (jcf); | |
3ca8c9ae | 177 | |
c2e3db92 KG |
178 | jcf->filename = xstrdup (zipfile); |
179 | jcf->classname = xstrdup (zipmember); | |
a4796c80 PB |
180 | return read_zip_member(jcf, zipd, zipf); |
181 | } | |
182 | } | |
183 | return -1; | |
184 | } | |
185 | ||
186 | /* Read data from zip archive member. */ | |
187 | ||
188 | int | |
189 | DEFUN(read_zip_member, (jcf, zipd, zipf), | |
190 | JCF *jcf AND ZipDirectory *zipd AND ZipFile *zipf) | |
191 | { | |
192 | jcf->filbuf = jcf_unexpected_eof; | |
e04a16fb | 193 | jcf->zipd = (void *)zipd; |
3ca8c9ae AG |
194 | |
195 | if (zipd->compression_method == Z_NO_COMPRESSION) | |
196 | { | |
197 | jcf->buffer = ALLOC (zipd->size); | |
198 | jcf->buffer_end = jcf->buffer + zipd->size; | |
199 | jcf->read_ptr = jcf->buffer; | |
200 | jcf->read_end = jcf->buffer_end; | |
201 | if (lseek (zipf->fd, zipd->filestart, 0) < 0 | |
962584ea | 202 | || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size) |
3ca8c9ae AG |
203 | return -2; |
204 | } | |
205 | else | |
206 | { | |
207 | char *buffer; | |
a4796c80 PB |
208 | z_stream d_stream; /* decompression stream */ |
209 | d_stream.zalloc = (alloc_func) 0; | |
210 | d_stream.zfree = (free_func) 0; | |
211 | d_stream.opaque = (voidpf) 0; | |
212 | ||
3ca8c9ae AG |
213 | jcf->buffer = ALLOC (zipd->uncompressed_size); |
214 | d_stream.next_out = jcf->buffer; | |
215 | d_stream.avail_out = zipd->uncompressed_size; | |
216 | jcf->buffer_end = jcf->buffer + zipd->uncompressed_size; | |
217 | jcf->read_ptr = jcf->buffer; | |
218 | jcf->read_end = jcf->buffer_end; | |
219 | buffer = ALLOC (zipd->size); | |
220 | d_stream.next_in = buffer; | |
221 | d_stream.avail_in = zipd->size; | |
222 | if (lseek (zipf->fd, zipd->filestart, 0) < 0 | |
962584ea | 223 | || read (zipf->fd, buffer, zipd->size) != (long) zipd->size) |
3ca8c9ae AG |
224 | return -2; |
225 | /* Handle NO_HEADER using undocumented zlib feature. | |
226 | This is a very common hack. */ | |
227 | inflateInit2 (&d_stream, -MAX_WBITS); | |
228 | inflate (&d_stream, Z_NO_FLUSH); | |
229 | inflateEnd (&d_stream); | |
230 | FREE (buffer); | |
231 | } | |
232 | ||
e04a16fb | 233 | return 0; |
e04a16fb | 234 | } |
e04a16fb | 235 | |
3b304f5b | 236 | const char * |
fc45c7ef | 237 | DEFUN(open_class, (filename, jcf, fd, dep_name), |
3b304f5b | 238 | const char *filename AND JCF *jcf AND int fd AND const char *dep_name) |
e04a16fb AG |
239 | { |
240 | if (jcf) | |
241 | { | |
242 | struct stat stat_buf; | |
243 | if (fstat (fd, &stat_buf) != 0 | |
244 | || ! S_ISREG (stat_buf.st_mode)) | |
245 | { | |
246 | perror ("Could not figure length of .class file"); | |
247 | return NULL; | |
248 | } | |
fc45c7ef TT |
249 | if (dep_name != NULL) |
250 | jcf_dependency_add_file (dep_name, 0); | |
e04a16fb AG |
251 | JCF_ZERO (jcf); |
252 | jcf->buffer = ALLOC (stat_buf.st_size); | |
253 | jcf->buffer_end = jcf->buffer + stat_buf.st_size; | |
254 | jcf->read_ptr = jcf->buffer; | |
255 | jcf->read_end = jcf->buffer_end; | |
256 | jcf->read_state = NULL; | |
257 | jcf->filename = filename; | |
258 | if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size) | |
259 | { | |
260 | perror ("Failed to read .class file"); | |
261 | return NULL; | |
262 | } | |
263 | close (fd); | |
264 | jcf->filbuf = jcf_unexpected_eof; | |
265 | } | |
266 | else | |
267 | close (fd); | |
268 | return filename; | |
269 | } | |
e04a16fb AG |
270 | |
271 | ||
c8e7d2e6 | 272 | const char * |
fc45c7ef | 273 | DEFUN(find_classfile, (filename, jcf, dep_name), |
4bcde32e | 274 | char *filename AND JCF *jcf AND const char *dep_name) |
e04a16fb | 275 | { |
e04a16fb AG |
276 | int fd = open (filename, O_RDONLY | O_BINARY); |
277 | if (fd < 0) | |
278 | return NULL; | |
fc45c7ef | 279 | return open_class (filename, jcf, fd, dep_name); |
e04a16fb AG |
280 | } |
281 | ||
a15135c9 MM |
282 | #if JCF_USE_SCANDIR |
283 | ||
284 | /* A comparison function (as for qsort) that compares KEY (a char * | |
285 | giving the basename of a file) with the name stored in ENTRY (a | |
286 | dirent **). */ | |
287 | ||
288 | static int | |
289 | DEFUN(compare_path, (key, entry), | |
290 | const void *key AND const void *entry) | |
291 | { | |
292 | return strcmp ((const char *) key, | |
293 | (*((const struct dirent **) entry))->d_name); | |
294 | } | |
295 | ||
296 | /* Returns nonzero if ENTRY names a .java or .class file. */ | |
297 | ||
298 | static int | |
299 | DEFUN(java_or_class_file, (entry), | |
300 | const struct dirent *entry) | |
301 | { | |
302 | const char *base = basename (entry->d_name); | |
303 | return (fnmatch ("*.java", base, 0) == 0 || | |
304 | fnmatch ("*.class", base, 0) == 0); | |
305 | } | |
306 | ||
307 | /* Information about the files present in a particular directory. */ | |
308 | typedef struct memoized_dirlist_entry | |
309 | { | |
310 | /* The name of the directory. */ | |
311 | const char *dir; | |
312 | /* The number of .java and .class files present, or -1 if we could | |
313 | not, for some reason, obtain the list. */ | |
314 | int num_files; | |
315 | /* The .java and .class files in the directory, in alphabetical | |
316 | order. */ | |
317 | struct dirent **files; | |
318 | } memoized_dirlist_entry; | |
319 | ||
320 | /* Returns true if ENTRY (a memoized_dirlist_entry *) correponds to | |
321 | the directory given by KEY (a char *) giving the directory | |
322 | name. */ | |
323 | ||
324 | static int | |
325 | DEFUN(memoized_dirlist_lookup_eq, (entry, key), | |
326 | const void *entry AND const void *key) | |
327 | { | |
328 | return strcmp ((const char *) key, | |
329 | ((const memoized_dirlist_entry *) entry)->dir) == 0; | |
330 | } | |
331 | ||
332 | /* A hash table mapping directory names to the lists of .java and | |
333 | .class files in that directory. */ | |
334 | ||
335 | static htab_t memoized_dirlists; | |
336 | ||
337 | #endif | |
338 | ||
339 | /* Like stat, but avoids actually making the stat system call if we | |
340 | know that it cannot succeed. FILENAME and BUF are as for stat. */ | |
341 | ||
342 | static int | |
343 | DEFUN(caching_stat, (filename, buf), | |
344 | char *filename AND struct stat *buf) | |
345 | { | |
346 | #if JCF_USE_SCANDIR | |
347 | char *sep; | |
348 | char *base; | |
349 | memoized_dirlist_entry *dent; | |
350 | void **slot; | |
351 | ||
352 | /* If the hashtable has not already been created, create it now. */ | |
353 | if (!memoized_dirlists) | |
354 | memoized_dirlists = htab_create (37, | |
355 | htab_hash_string, | |
356 | memoized_dirlist_lookup_eq, | |
357 | NULL); | |
358 | ||
359 | /* Get the name of the directory. */ | |
360 | sep = strrchr (filename, DIR_SEPARATOR); | |
361 | if (sep) | |
362 | { | |
363 | *sep = '\0'; | |
364 | base = sep + 1; | |
365 | } | |
366 | else | |
367 | base = filename; | |
368 | ||
369 | /* Obtain the entry for this directory form the hash table. */ | |
370 | slot = htab_find_slot (memoized_dirlists, filename, INSERT); | |
371 | if (!*slot) | |
372 | { | |
373 | /* We have not already scanned this directory; scan it now. */ | |
374 | dent = ((memoized_dirlist_entry *) | |
375 | ALLOC (sizeof (memoized_dirlist_entry))); | |
376 | dent->dir = xstrdup (filename); | |
377 | /* Unfortunately, scandir is not fully standardized. In | |
378 | particular, the type of the function pointer passed as the | |
379 | third argument sometimes takes a "const struct dirent *" | |
380 | parameter, and sometimes just a "struct dirent *". We rely | |
381 | on the ability to interchange these two types of function | |
382 | pointers. */ | |
383 | dent->num_files = scandir (filename, &dent->files, | |
384 | java_or_class_file, | |
385 | alphasort); | |
386 | *slot = dent; | |
387 | } | |
388 | else | |
389 | dent = *((memoized_dirlist_entry **) slot); | |
390 | ||
391 | /* Put the spearator back. */ | |
392 | if (sep) | |
393 | *sep = DIR_SEPARATOR; | |
394 | ||
395 | /* If the file is not in the list, there is no need to stat it; it | |
396 | does not exist. */ | |
397 | if (dent->num_files != -1 | |
398 | && !bsearch (base, dent->files, dent->num_files, | |
399 | sizeof (struct dirent *), compare_path)) | |
400 | return -1; | |
401 | #endif | |
402 | ||
403 | return stat (filename, buf); | |
404 | } | |
405 | ||
406 | /* Returns 1 if the CLASSNAME (really a char *) matches the name | |
407 | stored in TABLE_ENTRY (also a char *). */ | |
408 | ||
409 | static int | |
410 | DEFUN(memoized_class_lookup_eq, (table_entry, classname), | |
411 | const void *table_entry AND const void *classname) | |
412 | { | |
413 | return strcmp ((const char *)classname, (const char *)table_entry) == 0; | |
414 | } | |
415 | ||
416 | /* A hash table keeping track of class names that were not found | |
417 | during class lookup. (There is no need to cache the values | |
418 | associated with names that were found; they are saved in | |
419 | IDENTIFIER_CLASS_VALUE.) */ | |
420 | static htab_t memoized_class_lookups; | |
421 | ||
e04a16fb | 422 | /* Returns a freshly malloc'd string with the fully qualified pathname |
a15135c9 MM |
423 | of the .class file for the class CLASSNAME. CLASSNAME must be |
424 | allocated in permanent storage; this function may retain a pointer | |
425 | to it. Returns NULL on failure. If JCF != NULL, it is suitably | |
426 | initialized. SOURCE_OK is true if we should also look for .java | |
427 | file. */ | |
e04a16fb | 428 | |
c8e7d2e6 | 429 | const char * |
502f194f PB |
430 | DEFUN(find_class, (classname, classname_length, jcf, source_ok), |
431 | const char *classname AND int classname_length AND JCF *jcf AND int source_ok) | |
e04a16fb AG |
432 | |
433 | { | |
e04a16fb | 434 | int fd; |
502f194f | 435 | int i, k, java = -1, class = -1; |
e04a16fb | 436 | struct stat java_buf, class_buf; |
fc45c7ef | 437 | char *dep_file; |
502f194f | 438 | void *entry; |
8603f9c5 | 439 | char *java_buffer; |
a15135c9 MM |
440 | int buflen; |
441 | char *buffer; | |
442 | hashval_t hash; | |
443 | ||
444 | /* Create the hash table, if it does not already exist. */ | |
445 | if (!memoized_class_lookups) | |
446 | memoized_class_lookups = htab_create (37, | |
447 | htab_hash_string, | |
448 | memoized_class_lookup_eq, | |
449 | NULL); | |
450 | ||
451 | /* Loop for this class in the hashtable. If it is present, we've | |
452 | already looked for this class and failed to find it. */ | |
453 | hash = htab_hash_string (classname); | |
454 | if (htab_find_with_hash (memoized_class_lookups, classname, hash)) | |
455 | return NULL; | |
e04a16fb AG |
456 | |
457 | /* Allocate and zero out the buffer, since we don't explicitly put a | |
458 | null pointer when we're copying it below. */ | |
a15135c9 | 459 | buflen = jcf_path_max_len () + classname_length + 10; |
a92cb0c3 | 460 | buffer = ALLOC (buflen); |
961192e1 | 461 | memset (buffer, 0, buflen); |
e04a16fb | 462 | |
a92cb0c3 | 463 | java_buffer = alloca (buflen); |
fc45c7ef | 464 | |
ee07f4f4 | 465 | jcf->java_source = 0; |
8603f9c5 TT |
466 | |
467 | for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry)) | |
e04a16fb | 468 | { |
c8e7d2e6 | 469 | const char *path_name = jcf_path_name (entry); |
502f194f PB |
470 | if (class != 0) |
471 | { | |
472 | int dir_len; | |
8603f9c5 | 473 | |
502f194f PB |
474 | strcpy (buffer, path_name); |
475 | i = strlen (buffer); | |
8603f9c5 | 476 | |
502f194f PB |
477 | /* This is right because we know that `.zip' entries will have a |
478 | trailing slash. See jcf-path.c. */ | |
479 | dir_len = i - 1; | |
8603f9c5 | 480 | |
502f194f PB |
481 | for (k = 0; k < classname_length; k++, i++) |
482 | { | |
483 | char ch = classname[k]; | |
484 | buffer[i] = ch == '.' ? '/' : ch; | |
485 | } | |
486 | strcpy (buffer+i, ".class"); | |
8603f9c5 | 487 | |
502f194f | 488 | if (jcf_path_is_zipfile (entry)) |
e04a16fb | 489 | { |
502f194f PB |
490 | int err_code; |
491 | JCF _jcf; | |
492 | buffer[dir_len] = '\0'; | |
493 | SOURCE_FRONTEND_DEBUG | |
494 | (("Trying [...%s]:%s", | |
495 | &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], | |
496 | buffer+dir_len+1)); | |
497 | if (jcf == NULL) | |
498 | jcf = &_jcf; | |
499 | err_code = open_in_zip (jcf, buffer, buffer+dir_len+1, | |
500 | jcf_path_is_system (entry)); | |
501 | if (err_code == 0) | |
e04a16fb | 502 | { |
502f194f | 503 | /* Should we check if .zip is out-of-date wrt .java? */ |
8603f9c5 TT |
504 | buffer[dir_len] = '('; |
505 | strcpy (buffer+i, ".class)"); | |
502f194f PB |
506 | if (jcf == &_jcf) |
507 | JCF_FINISH (jcf); | |
508 | return buffer; | |
e04a16fb | 509 | } |
502f194f PB |
510 | else |
511 | continue; | |
e04a16fb | 512 | } |
a15135c9 | 513 | class = caching_stat(buffer, &class_buf); |
8603f9c5 TT |
514 | } |
515 | ||
502f194f | 516 | if (source_ok) |
8603f9c5 | 517 | { |
502f194f PB |
518 | /* Compute name of .java file. */ |
519 | int l, m; | |
520 | strcpy (java_buffer, path_name); | |
521 | l = strlen (java_buffer); | |
522 | for (m = 0; m < classname_length; ++m) | |
523 | java_buffer[m + l] = (classname[m] == '.' ? '/' : classname[m]); | |
524 | strcpy (java_buffer + m + l, ".java"); | |
a15135c9 | 525 | java = caching_stat (java_buffer, &java_buf); |
502f194f PB |
526 | if (java == 0) |
527 | break; | |
8603f9c5 | 528 | } |
0ef38928 | 529 | } |
8603f9c5 | 530 | |
ee07f4f4 APB |
531 | /* We preferably pick a class file if we have a chance. If the source |
532 | file is newer than the class file, we issue a warning and parse the | |
533 | source file instead. | |
534 | There should be a flag to allow people have the class file picked | |
535 | up no matter what. FIXME. */ | |
8000caee | 536 | if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime) |
ee07f4f4 | 537 | { |
b7436b72 | 538 | if (flag_newer) |
c725bd79 | 539 | warning ("source file for class `%s' is newer than its matching class file. Source file `%s' used instead", classname, java_buffer); |
ee07f4f4 APB |
540 | class = -1; |
541 | } | |
8603f9c5 | 542 | |
0ef38928 PB |
543 | if (! java) |
544 | dep_file = java_buffer; | |
545 | else | |
546 | dep_file = buffer; | |
0ef38928 PB |
547 | if (!class) |
548 | { | |
ee07f4f4 APB |
549 | SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n", |
550 | classname+classname_length- | |
551 | (classname_length <= 30 ? | |
552 | classname_length : 30))); | |
0ef38928 PB |
553 | fd = open (buffer, O_RDONLY | O_BINARY); |
554 | if (fd >= 0) | |
555 | goto found; | |
556 | } | |
557 | /* Give .java a try, if necessary */ | |
558 | if (!java) | |
559 | { | |
560 | strcpy (buffer, java_buffer); | |
ee07f4f4 APB |
561 | SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n", |
562 | classname+classname_length- | |
563 | (classname_length <= 30 ? | |
564 | classname_length : 30))); | |
0ef38928 PB |
565 | fd = open (buffer, O_RDONLY); |
566 | if (fd >= 0) | |
8603f9c5 | 567 | { |
0ef38928 PB |
568 | jcf->java_source = 1; |
569 | goto found; | |
e04a16fb AG |
570 | } |
571 | } | |
0ef38928 | 572 | |
e04a16fb | 573 | free (buffer); |
a15135c9 MM |
574 | |
575 | /* Remember that this class could not be found so that we do not | |
576 | have to look again. */ | |
577 | *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT) | |
578 | = (void *) classname; | |
579 | ||
e04a16fb AG |
580 | return NULL; |
581 | found: | |
e04a16fb AG |
582 | if (jcf->java_source) |
583 | { | |
584 | JCF_ZERO (jcf); /* JCF_FINISH relies on this */ | |
585 | jcf->java_source = 1; | |
c2e3db92 | 586 | jcf->filename = xstrdup (buffer); |
e04a16fb AG |
587 | close (fd); /* We use STDIO for source file */ |
588 | } | |
502f194f | 589 | else |
3b304f5b | 590 | buffer = (char *) open_class (buffer, jcf, fd, dep_file); |
c2e3db92 | 591 | jcf->classname = xstrdup (classname); |
e04a16fb | 592 | return buffer; |
e04a16fb AG |
593 | } |
594 | ||
595 | void | |
596 | DEFUN(jcf_print_char, (stream, ch), | |
597 | FILE *stream AND int ch) | |
598 | { | |
599 | switch (ch) | |
600 | { | |
601 | case '\'': | |
602 | case '\\': | |
603 | case '\"': | |
604 | fprintf (stream, "\\%c", ch); | |
605 | break; | |
606 | case '\n': | |
607 | fprintf (stream, "\\n"); | |
608 | break; | |
609 | case '\t': | |
610 | fprintf (stream, "\\t"); | |
611 | break; | |
612 | case '\r': | |
613 | fprintf (stream, "\\r"); | |
614 | break; | |
615 | default: | |
616 | if (ch >= ' ' && ch < 127) | |
617 | putc (ch, stream); | |
618 | else if (ch < 256) | |
619 | fprintf (stream, "\\%03x", ch); | |
620 | else | |
621 | fprintf (stream, "\\u%04x", ch); | |
622 | } | |
623 | } | |
624 | ||
625 | /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */ | |
626 | ||
627 | void | |
628 | DEFUN(jcf_print_utf8, (stream, str, length), | |
4bcde32e | 629 | FILE *stream AND register const unsigned char *str AND int length) |
e04a16fb | 630 | { |
4bcde32e | 631 | const unsigned char * limit = str + length; |
e04a16fb AG |
632 | while (str < limit) |
633 | { | |
634 | int ch = UTF8_GET (str, limit); | |
635 | if (ch < 0) | |
636 | { | |
637 | fprintf (stream, "\\<invalid>"); | |
638 | return; | |
639 | } | |
640 | jcf_print_char (stream, ch); | |
641 | } | |
642 | } | |
643 | ||
644 | /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */ | |
645 | ||
646 | void | |
647 | DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char), | |
4bcde32e | 648 | FILE *stream AND const unsigned char *str AND int length |
e04a16fb AG |
649 | AND int in_char AND int out_char) |
650 | { | |
d8b6d4cf TT |
651 | const unsigned char *limit = str + length; |
652 | while (str < limit) | |
e04a16fb | 653 | { |
d8b6d4cf TT |
654 | int ch = UTF8_GET (str, limit); |
655 | if (ch < 0) | |
656 | { | |
657 | fprintf (stream, "\\<invalid>"); | |
658 | return; | |
659 | } | |
e04a16fb AG |
660 | jcf_print_char (stream, ch == in_char ? out_char : ch); |
661 | } | |
662 | } | |
663 | ||
664 | /* Check that all the cross-references in the constant pool are | |
665 | valid. Returns 0 on success. | |
bc8a5e56 PB |
666 | Otherwise, returns the index of the (first) invalid entry. |
667 | Only checks internal consistency, but does not check that | |
668 | any classes, fields, or methods are valid.*/ | |
e04a16fb AG |
669 | |
670 | int | |
671 | DEFUN(verify_constant_pool, (jcf), | |
672 | JCF *jcf) | |
673 | { | |
674 | int i, n; | |
675 | for (i = 1; i < JPOOL_SIZE (jcf); i++) | |
676 | { | |
677 | switch (JPOOL_TAG (jcf, i)) | |
678 | { | |
679 | case CONSTANT_NameAndType: | |
680 | n = JPOOL_USHORT2 (jcf, i); | |
681 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
682 | || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) | |
683 | return i; | |
684 | /* ... fall through ... */ | |
685 | case CONSTANT_Class: | |
686 | case CONSTANT_String: | |
687 | n = JPOOL_USHORT1 (jcf, i); | |
688 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
689 | || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) | |
690 | return i; | |
691 | break; | |
692 | case CONSTANT_Fieldref: | |
693 | case CONSTANT_Methodref: | |
694 | case CONSTANT_InterfaceMethodref: | |
695 | n = JPOOL_USHORT1 (jcf, i); | |
696 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
697 | || JPOOL_TAG (jcf, n) != CONSTANT_Class) | |
698 | return i; | |
699 | n = JPOOL_USHORT2 (jcf, i); | |
700 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
701 | || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) | |
702 | return i; | |
703 | break; | |
704 | case CONSTANT_Long: | |
705 | case CONSTANT_Double: | |
706 | i++; | |
707 | break; | |
708 | case CONSTANT_Float: | |
709 | case CONSTANT_Integer: | |
710 | case CONSTANT_Utf8: | |
711 | case CONSTANT_Unicode: | |
712 | break; | |
713 | default: | |
714 | return i; | |
715 | } | |
716 | } | |
717 | return 0; | |
718 | } | |
719 | ||
720 | void | |
721 | DEFUN(format_uint, (buffer, value, base), | |
722 | char *buffer AND uint64 value AND int base) | |
723 | { | |
724 | #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8) | |
725 | char buf[WRITE_BUF_SIZE]; | |
726 | register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */ | |
727 | int chars_written; | |
728 | int i; | |
729 | ||
730 | /* Now do the actual conversion, placing the result at the *end* of buf. */ | |
731 | /* Note this code does not pretend to be optimized. */ | |
732 | do { | |
733 | int digit = value % base; | |
8b60264b | 734 | static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
e04a16fb AG |
735 | *--buf_ptr = digit_chars[digit]; |
736 | value /= base; | |
737 | } while (value != 0); | |
738 | ||
739 | chars_written = buf+WRITE_BUF_SIZE - buf_ptr; | |
740 | for (i = 0; i < chars_written; i++) | |
741 | buffer[i] = *buf_ptr++; | |
742 | buffer[i] = 0; | |
743 | } | |
744 | ||
745 | void | |
746 | DEFUN(format_int, (buffer, value, base), | |
747 | char *buffer AND jlong value AND int base) | |
748 | { | |
749 | uint64 abs_value; | |
750 | if (value < 0) | |
751 | { | |
752 | abs_value = -(uint64)value; | |
753 | *buffer++ = '-'; | |
754 | } | |
755 | else | |
756 | abs_value = (uint64) value; | |
757 | format_uint (buffer, abs_value, base); | |
758 | } |