1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 /* All Java Virtual Machine Specs are from
29 * "The Java Virtual Machine Specification", T. Lindholm, F. Yellin
41 #if defined(UNX) || defined(OS2)
43 #include <netinet/in.h> /* ntohl(), ntohs() */
46 #define access _access
47 #define vsnprintf _vsnprintf
50 #define PATH_MAX _MAX_PATH
51 #define ntohl(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
52 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
54 #define ntohs(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
61 /* max. length of line in response file */
62 #define RES_FILE_BUF 65536
75 typedef struct file file_t
;
76 typedef unsigned char uint8
;
77 typedef unsigned short uint16
;
78 typedef unsigned int uint32
;
85 typedef struct utf8 utf8_t
;
87 /* The contents of the Constant_pool is described in JVMS p. 93
91 CONSTANT_Fieldref
= 9,
92 CONSTANT_Methodref
= 10,
93 CONSTANT_InterfaceMethodref
= 11,
99 CONSTANT_NameAndType
= 12,
103 enum { NGROW_INIT
= 10, NGROW
= 2 };
105 static char *pprogname
= "javadep";
106 static char csep
= ';';
107 #if defined (UNX) || defined(OS2)
109 static char cpathsep
= '/';
110 #elif defined (WNT) || defined(OS2)
111 static char cpathsep
= '\\';
113 static FILE *pfsout
= NULL
;
114 static char *pout_file
= NULL
;
118 uint8
read_uint8(const file_t
*pfile
);
119 uint16
read_uint16(const file_t
*pfile
);
120 uint32
read_uint32(const file_t
*pfile
);
121 void skip_bytes(const file_t
*pfile
, const size_t nnum
);
122 char *escape_slash(const char *pstr
);
123 int is_inner(const char *pstr
);
124 void print_dependencies(const struct growable
*pdep
,
125 const char* pclass_file
);
126 void process_class_file(const char *pfilenamem
,
127 const struct growable
*pfilt
);
128 char *utf8tolatin1(const utf8_t a_utf8
);
129 void *xmalloc(size_t size
);
130 void *xcalloc(size_t nmemb
, size_t size
);
131 void *xrealloc(void *ptr
, size_t size
);
132 void grow_if_needed (struct growable
*pgrow
);
133 int append_to_growable(struct growable
*, char *);
134 struct growable
*allocate_growable(void);
135 void free_growable(struct growable
*pgrowvoid
);
136 void create_filters(struct growable
*pfilt
, const struct growable
*pinc
);
138 void err_quit(const char *, ...);
139 void silent_quit(void);
142 /* poor man's getopt() */
143 int simple_getopt(char *pargv
[], const char *poptstring
);
151 read_uint8(const file_t
*pfile
)
153 /* read a byte from classfile */
156 nread
= fread(&ndata
, sizeof(uint8
), 1, pfile
->pfs
);
159 err_quit("%s: truncated class file", pfile
->pname
);
165 read_uint16(const file_t
*pfile
)
167 /* read a short from classfile and convert it to host format */
170 nread
= fread(&ndata
, sizeof(uint16
), 1, pfile
->pfs
);
173 err_quit("%s: truncated class file", pfile
->pname
);
175 ndata
= ntohs(ndata
);
180 read_uint32(const file_t
*pfile
)
182 /* read an int from classfile and convert it to host format */
185 nread
= fread(&ndata
, sizeof(uint32
), 1, pfile
->pfs
);
188 err_quit("%s: truncated class file", pfile
->pname
);
190 ndata
= ntohl(ndata
);
195 read_utf8(const file_t
*pfile
)
197 /* Read a java utf-8-string with uint16 length prependend
198 * from class file. Returns utf8 struct
199 * with fresh allocated datablock,
200 * caller is responsible for freeing.
201 * Data is still in network byteorder
209 a_utf8
.nlen
= read_uint16(pfile
);
210 if (a_utf8
.nlen
> 0) {
211 a_utf8
.pdata
= xmalloc(a_utf8
.nlen
*sizeof(char));
212 nread
= fread(a_utf8
.pdata
, a_utf8
.nlen
*sizeof(char), 1, pfile
->pfs
);
215 err_quit("%s: truncated class file", pfile
->pname
);
222 char *utf8tolatin1(const utf8_t a_utf8
)
224 /* function returns fresh allocated zero terminated string,
225 * caller is responsible for freeing
228 /* JVMS p. 101: the null byte is encoded using a two byte format,
229 * Java Virtual Machine Utf8 strings differ in this respect from
230 * standard UTF-8 strings
233 /* Multibyte data is in network byte order */
239 pstr
= pp
= xmalloc((a_utf8
.nlen
+1) * sizeof(char));
241 for ( p
= (char*)a_utf8
.pdata
;
242 p
< (char*)a_utf8
.pdata
+a_utf8
.nlen
;
245 err_quit("sorry, real UTF8 decoding not yet implemented\n");
257 skip_bytes(const file_t
*pfile
, const size_t nnumber
)
259 /* skip a nnumber of bytes in classfile */
260 if ( fseek(pfile
->pfs
, nnumber
, SEEK_CUR
) == -1 )
261 err_quit("%s: %s", pfile
->pname
, strerror(errno
));
265 add_to_dependencies(struct growable
*pdep
,
266 const struct growable
*pfilt
,
268 const char *pclass_file
)
270 /* create dependencies */
272 int nlen_filt
, nlen_str
, nlen_pdepstr
;
274 char path
[PATH_MAX
+1];
275 char cnp_class_file
[PATH_MAX
+1];
276 char cnp_str
[PATH_MAX
+1];
278 nlen_pdepstr
= strlen(pdepstr
);
279 pstr
= xmalloc((nlen_pdepstr
+6+1)*sizeof(char));
280 memcpy(pstr
, pdepstr
, nlen_pdepstr
+1);
281 strncat(pstr
, ".class", 6);
283 if ( pfilt
->ncur
== 0 ) { /* no filters */
284 if ( access(pstr
, F_OK
) == 0 ) {
285 append_to_growable(pdep
, strdup(pstr
));
288 nlen_str
= strlen(pstr
);
289 for ( i
= 0; i
< pfilt
->ncur
; i
++ ) {
290 nlen_filt
= strlen(pfilt
->parray
[i
]);
291 if ( nlen_filt
+ 1 + nlen_str
> PATH_MAX
)
292 err_quit("path to long");
293 memcpy(path
, pfilt
->parray
[i
], nlen_filt
);
294 path
[nlen_filt
] = '/';
295 memcpy( path
+nlen_filt
+1, pstr
, nlen_str
+1);
297 if ( access(path
, F_OK
) != 0 ) {
300 return; /* path doesn't represent a real file, don't bother */
303 /* get the canonical path */
304 #if defined (UNX) || defined(OS2)
305 if ( !(realpath(pclass_file
, cnp_class_file
)
306 && realpath(path
, cnp_str
) ) ) {
307 err_quit("can't get the canonical path");
310 if ( !(_fullpath(cnp_class_file
, pclass_file
, sizeof(cnp_class_file
))
311 && _fullpath(cnp_str
, path
, sizeof(cnp_str
)) ) ) {
312 err_quit("can't get the canonical path");
316 /* truncate so that only the package prefix remains */
317 ptrunc
= strrchr(cnp_str
, cpathsep
);
319 ptrunc
= strrchr(cnp_class_file
, cpathsep
);
322 if ( !strcmp(cnp_str
, cnp_class_file
) ) {
325 return; /* identical, don't bother with this one */
328 append_to_growable(pdep
, strdup(path
));
336 escape_slash(const char *pstr
)
338 /* returns a fresh allocated string with all cpathsep escaped exchanged
341 * caller is responsible for freeing
344 const char *pp
= pstr
;
347 int nlen_pnp
, nlen_pp
;
350 while ( (p
=strchr(pp
, cpathsep
)) != NULL
) {
355 nlen_pnp
= strlen(pstr
) + i
;
356 pnp
= pnew_str
= xmalloc((nlen_pnp
+1) * sizeof(char));
361 while ( (p
=strchr(pp
, cpathsep
)) != NULL
) {
362 memcpy(pnp
, pp
, p
-pp
);
369 nlen_pp
= strlen(pp
);
370 memcpy(pnp
, pp
, nlen_pp
+1);
377 print_dependencies(const struct growable
*pdep
, const char* pclass_file
)
382 pstr
= escape_slash(pclass_file
);
383 fprintf(pfsout
, "%s:", pstr
);
386 for( i
=0; i
<pdep
->ncur
; ++i
) {
387 fprintf(pfsout
, " \\\n");
388 pstr
=escape_slash(pdep
->parray
[i
]);
389 fprintf(pfsout
, "\t%s", pstr
);
393 fprintf(pfsout
,"\n\n");
398 is_inner(const char *pstr
)
400 /* return true if character '$' is found in classname */
403 * note that a '$' in a classname is not an exact indicator
404 * for an inner class. Java identifier may legally contain
405 * this chararcter, and so may classnames. In the context
406 * of javadep this doesn't matter since the makefile system
407 * can't cope with classfiles with '$'s in the filename
412 if ( strchr(pstr
, '$') != NULL
)
419 process_class_file(const char *pfilename
, const struct growable
*pfilt
)
421 /* read class file and extract object information
422 * java class files are in bigendian data format
427 uint16 nminor
, nmajor
;
434 struct growable
*pdepen
;
436 file
.pname
= (char*)pfilename
;
438 file
.pfs
= fopen(file
.pname
,"rb");
442 nmagic
= read_uint32(&file
);
444 if ( nmagic
!= 0xCAFEBABE ) {
446 err_quit("%s: invalid magic", file
.pname
);
449 nminor
= read_uint16(&file
);
450 nmajor
= read_uint16(&file
);
452 /* get number of entries in constant pool */
453 ncnt
= read_uint16(&file
);
456 printf("Magic: %p\n", (void*)nmagic
);
457 printf("Major %d, Minor %d\n", nmajor
, nminor
);
458 printf("Const_pool_count %d\n", ncnt
);
461 /* There can be ncount entries in the constant_pool table
462 * so at most ncount-1 of them can be of type CONSTANT_Class
463 * (at leat one CONSTANT_Utf8 entry must exist).
464 * Usually way less CONSTANT_Class entries exists, of course
467 pc_pool
= xcalloc(ncnt
,sizeof(utf8_t
));
468 pc_class
= xmalloc((ncnt
-1)*sizeof(uint16
));
470 /* pc_pool[0] is reserved to the java virtual machine and does
471 * not exist in the class file
476 for (i
= 1; i
< ncnt
; i
++) {
481 ntag
= read_uint8(&file
);
483 /* we are only interested in CONSTANT_Class entries and
484 * Utf8 string entries, because they might belong to
485 * CONSTANT_Class entries
489 nindex
= read_uint16(&file
);
490 pc_class
[nclass_cnt
++] = nindex
;
492 case CONSTANT_Fieldref
:
493 case CONSTANT_Methodref
:
494 case CONSTANT_InterfaceMethodref
:
495 skip_bytes(&file
, 4L);
497 case CONSTANT_String
:
498 skip_bytes(&file
, 2L);
500 case CONSTANT_Integer
:
502 skip_bytes(&file
, 4L);
505 case CONSTANT_Double
:
506 skip_bytes(&file
, 8L);
507 /* Long and Doubles take 2(!)
508 * entries in constant_pool_table
512 case CONSTANT_NameAndType
:
513 skip_bytes(&file
, 4L);
516 a_utf8
= read_utf8(&file
);
520 /* Unknown Constant_pool entry, this means we are
523 err_quit("corrupted class file\n");
531 pdepen
= allocate_growable();
533 for (i
= 0; i
< nclass_cnt
; i
++) {
534 char *pstr
, *ptmpstr
;
535 pstr
= ptmpstr
= utf8tolatin1(pc_pool
[pc_class
[i
]]);
536 /* we are not interested in inner classes */
537 if ( is_inner(pstr
) ) {
542 /* strip off evt. array indicators */
543 if ( *ptmpstr
== '[' ) {
544 while ( *ptmpstr
== '[' )
546 /* we only interested in obj. arrays, which are marked with 'L' */
547 if ( *ptmpstr
== 'L' ) {
549 pstr
= strdup(++ptmpstr
);
550 /* remove final ';' from object array name */
551 pstr
[strlen(pstr
)-1] = '\0';
560 add_to_dependencies(pdepen
, pfilt
, pstr
, file
.pname
);
565 print_dependencies(pdepen
, file
.pname
);
566 free_growable(pdepen
);
569 for (i
= 0; i
< ncnt
; i
++)
570 free(pc_pool
[i
].pdata
);
584 err_quit("out of memory");
591 xcalloc(size_t nmemb
, size_t size
)
595 ptr
= calloc(nmemb
, size
);
598 err_quit("out of memory");
604 xrealloc(void *ptr
, size_t size
)
606 ptr
= realloc(ptr
, size
);
609 err_quit("out of memory");
615 err_quit(const char* fmt
, ...)
617 /* No dependency file must be generated for any error condition,
618 * just print message and exit.
621 char buffer
[PATH_MAX
];
626 fprintf(stderr
, "%s: ", pprogname
);
627 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
628 fputs(buffer
, stderr
);
634 if ( pfsout
&& pfsout
!= stdout
) {
644 /* In some cases we should just do a silent exit */
647 if ( pfsout
&& pfsout
!= stdout
) {
654 int append_to_growable(struct growable
*pgrow
, char *pstr
)
656 /* append an element pstr to pgrow,
657 * return new number of elements
659 grow_if_needed(pgrow
);
660 pgrow
->parray
[pgrow
->ncur
++] = pstr
;
665 grow_if_needed(struct growable
*pgrow
)
667 /* grow growable arrays */
669 if ( pgrow
->ncur
>= pgrow
->nmax
) {
670 pgrow
->parray
= xrealloc(pgrow
->parray
,
671 (NGROW
*pgrow
->nmax
)*sizeof(char*));
672 pgrow
->nmax
*= NGROW
;
677 struct growable
*allocate_growable(void)
679 /* allocate an growable array,
680 * initialize with NGROW_INIT elements
683 struct growable
*pgrow
;
685 pgrow
= xmalloc(sizeof(struct growable
));
686 pgrow
->parray
= xmalloc(NGROW_INIT
*sizeof(char *));
687 pgrow
->nmax
= NGROW_INIT
;
693 free_growable(struct growable
*pgrow
)
696 for( i
= 0; i
< pgrow
->ncur
; i
++ )
697 free(pgrow
->parray
[i
]);
703 create_filters(struct growable
*pfilt
, const struct growable
*pinc
)
706 int i
, nlen
, nlen_pstr
;
707 /* break up includes into filter list */
708 for ( i
= 0; i
< pinc
->ncur
; i
++ ) {
709 pp
= pinc
->parray
[i
];
711 while ( (p
= strchr(pp
, csep
)) != NULL
) {
713 pstr
= xmalloc((nlen
+1)*sizeof(char*));
714 memcpy(pstr
, pp
, nlen
);
716 append_to_growable(pfilt
, pstr
);
719 nlen_pstr
= strlen(pp
);
720 pstr
= xmalloc((nlen_pstr
+1)*sizeof(char*));
721 memcpy(pstr
, pp
, nlen_pstr
+1);
722 append_to_growable(pfilt
, pstr
);
731 "usage: %s [-i|-I includepath ... -s|-S seperator "
732 "-o|-O outpath -v|-V -h|-H] <file> ....\n",
736 /* my very simple minded implementation of getopt()
737 * it's to sad that getopt() is not available everywhere
738 * note: this is not a full POSIX conforming getopt()
740 int simple_getopt(char *pargv
[], const char *poptstring
)
742 char *parg
= pargv
[optind
];
744 /* skip all response file arguments */
746 while ( *parg
== '@' )
747 parg
= pargv
[++optind
];
749 if ( parg
[0] == '-' && parg
[1] != '\0' ) {
752 if ( (popt
= strchr(poptstring
, c
)) == NULL
) {
755 fprintf(stderr
, "Unknown option character `\\x%x'.\n", optopt
);
758 if ( *(++popt
) == ':') {
759 if ( parg
[2] != '\0' ) {
762 optarg
= pargv
[++optind
];
775 main(int argc
, char *argv
[])
778 struct growable
*presp
, *pincs
, *pfilters
;
782 presp
= allocate_growable();
784 /* FIXME: cleanup the option parsing */
785 /* search for response file, read it */
786 for ( i
= 1; i
< argc
; i
++ ) {
787 char *parg
= argv
[i
];
788 char buffer
[RES_FILE_BUF
];
790 if ( *parg
== '@' ) {
791 FILE *pfile
= fopen(++parg
, "r");
793 err_quit("%s: %s", parg
, strerror(errno
));
794 while ( !feof(pfile
) ) {
797 if ( fgets(buffer
, RES_FILE_BUF
, pfile
) ) {;
799 while ( (token
= strtok(p
, " \t\n")) != NULL
) {
801 append_to_growable(presp
, strdup(token
));
809 /* copy all arguments incl. response file in one array
810 * for parsing with getopt
812 nall_argc
= argc
+ presp
->ncur
;
813 pall_argv
= xmalloc((nall_argc
+1)*sizeof(char *));
814 memcpy(pall_argv
, argv
, argc
*sizeof(char *));
815 memcpy(pall_argv
+argc
, presp
->parray
, presp
->ncur
*sizeof(char *));
816 *(pall_argv
+argc
+presp
->ncur
) = '\0'; /* terminate */
819 pincs
= allocate_growable();
822 while( (c
= simple_getopt(pall_argv
, ":i:I:s:S:o:OhHvV")) != -1 ) {
824 while( (c
= getopt(nall_argc
, pall_argv
, ":i:I:s:S:o:OhHvV")) != -1 ) {
829 append_to_growable(pincs
, strdup(optarg
));
849 if (isprint (optopt
))
851 "Unknown option `-%c'.\n", optopt
);
854 "Unknown option character `\\x%x'.\n",
860 fprintf(stderr
, "Missing parameter.\n");
871 pfilters
= allocate_growable();
872 create_filters(pfilters
, pincs
);
873 free_growable(pincs
);
877 pfsout
= fopen(pout_file
, "w");
879 err_quit("%s: %s", pout_file
, strerror(errno
));
884 /* the remaining arguments are either class file
885 * names or response files, ignore response file
886 * since they have already been included
888 for ( i
= optind
; i
< nall_argc
; i
++ ) {
889 char *parg
= pall_argv
[i
];
890 if ( *parg
!= '@' ) {
891 process_class_file(parg
, pfilters
);
892 if ( pfsout
!= stdout
) {
894 printf("Processed %s ...\n", parg
);
899 free_growable(pfilters
);
903 free_growable(presp
);