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