]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/java/jcf-io.c
Merge basic-improvements-branch to trunk
[thirdparty/gcc.git] / gcc / java / jcf-io.c
CommitLineData
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
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2, or (at your option)
7any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with GNU CC; see the file COPYING. If not, write to
16the Free Software Foundation, 59 Temple Place - Suite 330,
17Boston, MA 02111-1307, USA.
18
19Java and all Java-based marks are trademarks or registered trademarks
20of Sun Microsystems, Inc. in the United States and other countries.
21The 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
47int
48DEFUN(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
58void
59DEFUN(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
71int
72DEFUN(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 100struct 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
107ZipFile *
108DEFUN(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 153int
502f194f 154DEFUN(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
188int
189DEFUN(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 236const char *
fc45c7ef 237DEFUN(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 272const char *
fc45c7ef 273DEFUN(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
288static int
289DEFUN(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
298static int
299DEFUN(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. */
308typedef 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
324static int
325DEFUN(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
335static 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
342static int
343DEFUN(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
409static int
410DEFUN(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.) */
420static 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 429const char *
502f194f
PB
430DEFUN(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
595void
596DEFUN(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
627void
628DEFUN(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
646void
647DEFUN(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
670int
671DEFUN(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
720void
721DEFUN(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
745void
746DEFUN(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}