/*
jartool.c - main functions for fastjar utility
- Copyright (C) 1999, 2000 Bryan Burns
+ Copyright (C) 2002 Free Software Foundation
+ Copyright (C) 1999, 2000, 2001 Bryan Burns
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/* $Id: jartool.c,v 1.2 2000/12/13 18:11:57 tromey Exp $
+/*
+ Revision 1.10 2002/01/03 04:57:56 rodrigc
+ 2001-01-02 Craig Rodrigues <rodrigc@gcc.gnu.org>
+
+ PR bootstrap/5117
+ * configure.in (AC_CHECK_HEADERS): Check for stdlib.h.
+ * Makefile.am: Move grepjar to bin_PROGRAMS.
+ * config.h.in: Regenerated.
+ * Makefile.in: Regenerated.
+ * aclocal.m4: Regenerated.
+ * jargrep.c: Eliminate some signed/unsigned and default
+ uninitialized warnings. Use HAVE_STDLIB_H instead of
+ STDC_HEADERS macro.
+ * jartool.c: Likewise.
+ * compress.c: Likewise.
+
+ Revision 1.9 2001/10/12 00:49:42 bryce
+ * jatool.c (extract_jar): Account for null termination when
+ determining whether to expand "filename".
+
+ Revision 1.8 2001/08/29 01:35:31 apbianco
+ 2001-08-28 Alexandre Petit-Bianco <apbianco@redhat.com>
+
+ * jartool.c (add_to_jar): Return 1 if `stat' initialy failed.
+ Fixes PR java/3949.
+
+ (http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01641.html)
+
+ Revision 1.7 2001/08/27 23:09:37 tromey
+ * jartool.c (jarfile): Remove length limitation.
+ (main): Use jt_strdup when initializing jarfile.
+
+ Revision 1.6 2001/07/04 18:33:53 tromey
+ Modified from patch by Julian Hall <jules@acris.co.uk>:
+ * jartool.c (errno): Conditionally declare.
+ (O_BINARY): Conditionally define.
+ (main): Use open, not creat. Use O_BINARY everywhere.
+ (make_manifest): Use O_BINARY.
+ (add_to_jar): Likewise.
+
+ Revision 1.5 2001/05/03 21:40:47 danglin
+ * jartool.c (jt_strdup): New function.
+ (get_next_arg): Use jt_strdup instead of strdup.
+
+ Revision 1.4 2000/12/28 21:47:37 robertl
+ 2000-12-28 Robert Lipe <robertl@sco.com>
+
+ * jartool.c (MAXPATHLEN): Provide if not defined.
+
+ Revision 1.3 2000/12/14 18:45:35 ghazi
+ Warning fixes:
+
+ * compress.c: Include stdlib.h and compress.h.
+ (rcsid): Delete.
+ (report_str_error): Make static.
+ (ez_inflate_str): Delete unused variable. Add parens in if-stmt.
+ (hrd_inflate_str): Likewise.
+
+ * compress.h (init_compression, end_compression, init_inflation,
+ end_inflation): Prototype void arguments.
+
+ * dostime.c (rcsid): Delete.
+
+ * jargrep.c: Include ctype.h, stdlib.h, zlib.h and compress.h.
+ Make functions static. Cast ctype function argument to `unsigned
+ char'. Add parens in if-stmts. Constify.
+ (Usage): Change into a macro.
+ (jargrep): Remove unused parameter.
+
+ * jartool.c: Constify. Add parens in if-stmts. Align
+ signed/unsigned char pointers in functions calls using casts.
+ (rcsid): Delete.
+ (list_jar): Fix printf format specifier.
+ (usage): Chop long string into bits. Reformat.
+
+ * pushback.c (rcsid): Delete.
- $Log: jartool.c,v $
Revision 1.2 2000/12/13 18:11:57 tromey
* jartool.c (extract_jar): Use strchr, not index.
#include <zlib.h>
-#ifdef STDC_HEADERS
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
-#else
+#endif
+
+#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#include <time.h>
#endif
+#include <getopt.h>
+
#include "jartool.h"
#include "zipfile.h"
#include "dostime.h"
#endif
-static char version_string[] = VERSION;
-
+#ifndef errno
extern int errno;
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
void usage(const char*);
+void help(const char *);
+void version(void);
void add_entry(struct zipentry *);
void init_headers(void);
int make_manifest(int, const char*);
static void init_args(char **, int);
static char *get_next_arg (void);
+static char *jt_strdup (char*);
+static void expand_options (int *argcp, char ***argvp);
/* global variables */
ub1 file_header[30];
int do_compress;
int seekable;
int verbose;
-char jarfile[256];
+char *jarfile;
/* If non zero, then don't recurse in directory. Instead, add the
directory entry and relie on an explicit list of files to populate
int number_of_entries; /* number of entries in the linked list */
+/* This is used to mark options with no short value. */
+#define LONG_OPT(Num) ((Num) + 128)
+
+#define OPT_HELP LONG_OPT (0)
+
+/* This holds all options except `-C', which is handled specially. */
+#define OPTION_STRING "-ctxuvVf:m:0ME@"
+
+static const struct option options[] =
+{
+ { "help", no_argument, NULL, OPT_HELP },
+ { "version", no_argument, NULL, 'V' },
+ { NULL, no_argument, NULL, 0 }
+};
+
int main(int argc, char **argv){
- char mfile[256];
+ char *mfile = NULL;
int action = ACTION_NONE;
int manifest = TRUE;
- int manifest_file = FALSE;
- int file = FALSE;
- int file_first = FALSE;
+ int opt;
- int i, j;
+ int j;
int jarfd = -1;
+ /* These are used to collect file names and `-C' options for the
+ second pass through the command line. */
+ int new_argc;
+ char **new_argv;
+
do_compress = TRUE;
verbose = FALSE;
j = strlen(argv[1]);
- for(i = 0; i < j; i++){
- switch(argv[1][i]){
+ new_argc = 0;
+ new_argv = (char **) malloc (argc * sizeof (char *));
+
+ expand_options (&argc, &argv);
+ while ((opt = getopt_long (argc, argv, OPTION_STRING,
+ options, NULL)) != -1) {
+ switch(opt){
+ case 1:
+ /* File name or unparsed option, due to RETURN_IN_ORDER. In
+ particular `-C' is handled here and not elsewhere. */
+ new_argv[new_argc++] = optarg;
+ break;
case 'c':
action = ACTION_CREATE;
break;
verbose = TRUE;
break;
case 'V':
- printf("%s\n", version_string);
+ version();
exit(0);
case 'f':
- file = TRUE;
- if(!manifest_file)
- file_first = TRUE;
- else
- file_first = FALSE;
+ jarfile = optarg;
break;
case 'm':
- manifest_file = TRUE;
+ mfile = optarg;
break;
case '0':
do_compress = FALSE;
case 'M':
manifest = FALSE;
break;
- case '-':
+
+ case OPT_HELP:
+ help(argv[0]);
break;
+
/* The following options aren't supported by the original jar tool. */
case 'E':
use_explicit_list_only = TRUE;
read_names_from_stdin = TRUE;
break;
default:
- fprintf(stderr, "Illegal option: %c\n", argv[1][i]);
usage(argv[0]);
}
}
+ /* We might have seen `--'. In this case we want to make sure that
+ all following options are handled as file names. */
+ while (optind < argc)
+ new_argv[new_argc++] = argv[optind++];
+
if(action == ACTION_NONE){
fprintf(stderr, "One of options -{ctxu} must be specified.\n");
usage(argv[0]);
}
+ if(action == ACTION_UPDATE){
+ fprintf(stderr, "%s: `-u' mode unimplemented.\n", argv[0]);
+ exit(1);
+ }
+
/* Verify unsupported combinations and warn of the use of non
standard features */
if(verbose && use_explicit_list_only)
usage(argv[0]);
}
- i = 2;
-
- /* get the jarfile and manifest file (if any) */
- if(file && file_first){
- if(i >= argc)
- usage(argv[0]);
-
- strncpy(jarfile, argv[i++], 256);
- }
- if(manifest_file){
- if(i >= argc)
- usage(argv[0]);
-
- strncpy(mfile, argv[i++], 256);
- }
-
- if(file && !file_first){
- if(i >= argc)
- usage(argv[0]);
-
- strncpy(jarfile, argv[i++], 256);
- }
-
/* create the jarfile */
if(action == ACTION_CREATE){
- if(file){
- jarfd = creat(jarfile, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
+ if(jarfile){
+ jarfd = open(jarfile, O_CREAT | O_BINARY | O_WRONLY | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
if(jarfd < 0){
fprintf(stderr, "Error opening %s for writing!\n", jarfile);
perror(jarfile);
}
} else if(action == ACTION_LIST || action == ACTION_EXTRACT){
- if(file){
- jarfd = open(jarfile, O_RDONLY);
+ if(jarfile){
+ jarfd = open(jarfile, O_RDONLY | O_BINARY);
if(jarfd < 0){
fprintf(stderr, "Error opening %s for reading!\n", jarfile);
const char *arg;
init_headers();
- if((action == ACTION_UPDATE) && file) {
- if((jarfd = open(jarfile, O_RDWR)) < 0) {
+ if((action == ACTION_UPDATE) && jarfile) {
+ if((jarfd = open(jarfile, O_RDWR | O_BINARY)) < 0) {
fprintf(stderr, "Error opening %s for reading!\n", jarfile);
perror(jarfile);
exit(1);
/* Add the META-INF/ directory and the manifest */
- if(manifest && manifest_file)
+ if(manifest && mfile)
make_manifest(jarfd, mfile);
else if(manifest)
make_manifest(jarfd, NULL);
- init_args (argv, i);
+ init_args (new_argv, new_argc);
/* now we add the files to the archive */
while ((arg = get_next_arg ())){
fprintf(stderr, "Error closing jar archive!\n");
}
} else if(action == ACTION_LIST){
- list_jar(jarfd, &argv[i], (argc - i));
+ list_jar(jarfd, &new_argv[0], new_argc);
} else if(action == ACTION_EXTRACT){
- extract_jar(jarfd, &argv[i], (argc - i));
+ extract_jar(jarfd, &new_argv[0], new_argc);
}
exit(0);
if (pos)
{
s [pos] = '\0';
- return strdup (s);
+ return jt_strdup (s);
}
else
return NULL;
exit(1);
}
- mfd = open(mf_name, O_RDONLY);
+ mfd = open(mf_name, O_RDONLY | O_BINARY);
if(mfd < 0){
fprintf(stderr, "Error opening %s.\n", mf_name);
if(stat_return == -1){
perror(file);
+ return 1;
} else if(S_ISDIR(statbuf.st_mode)){
char *fullname;
char *t_ptr;
} else if(S_ISREG(statbuf.st_mode)){
int add_fd;
- add_fd = open(file, O_RDONLY);
+ add_fd = open(file, O_RDONLY | O_BINARY);
if(add_fd < 0){
fprintf(stderr, "Error opening %s.\n", file);
return 0;
#endif
}
- if(filename_len < fnlen){
+ if(filename_len < fnlen + 1){
if(filename != NULL)
free(filename);
ze.crc = crc32(ze.crc, NULL, 0); /* initialize the crc */
- while(out_a < csize){
+ while(out_a < (int)csize){
rdamt = (in_a > RDSZ ? RDSZ : in_a);
if(pb_read(&pbf, rd_buff, rdamt) != rdamt){
perror("read");
/* printf("Central header offset = %d\n", tmp); */
- if(lseek(fd, tmp, SEEK_SET) != tmp){
+ if(lseek(fd, tmp, SEEK_SET) != (int)tmp){
perror("lseek");
exit(1);
}
}
void usage(const char *filename){
- fprintf(stderr, "\
+ fprintf(stderr, "Try `%s --help' for more information.\n", filename);
+ exit (1);
+}
+
+void version ()
+{
+ printf("jar (%s) %s\n\n", PACKAGE, VERSION);
+ printf("Copyright 1999, 2000, 2001 Bryan Burns\n");
+ printf("Copyright 2002 Free Software Foundation\n");
+ printf("\
+This is free software; see the source for copying conditions. There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+ exit (0);
+}
+
+void help(const char *filename)
+{
+ printf("\
Usage: %s {ctxuV}[vfm0ME@] [jar-file] [manifest-file] [-C dir] files ...\n\
-Options\n\
- -c create new archive\n\
- -t list table of contents for archive\n\
- -x extract named (or all) files from archive\n\
+\n\
+Store many files together in a single `jar' file.\n\
+\n\
+ -c create new archive\n\
+ -t list table of contents for archive\n\
+ -x extract named (or all) files from archive\n\
+ -u update existing archive\n\
", filename);
- fprintf(stderr, "\
- -u update existing archive\n\
- -V display version information\n\
- -v generate verbose output on standard output\n\
- -f specify archive file name\n\
- -m include manifest information from specified manifest file\n\
- -0 store only; use no ZIP compression\n\
- -M Do not create a manifest file for the entries\n\
- -C change to the specified directory and include the following file\n\
- -E don't include the files found in a directory\n\
- -@ Read names from stdin\n\
+ printf("\n\
+ -@ read names from stdin\n\
+ -0 store only; use no ZIP compression\n\
+ -C DIR FILE change to the specified directory and include\n\
+ the following file\n\
+ -E don't include the files found in a directory\n\
+ -f FILE specify archive file name\n\
+ --help print this help, then exit\n\
+ -m FILE include manifest information from specified manifest file\n\
+ -M Do not create a manifest file for the entries\n\
+ -v generate verbose output on standard output\n\
+ -V, --version display version information\n\
");
- fprintf(stderr, "\
+ printf("\n\
If any file is a directory then it is processed recursively.\n\
The manifest file name and the archive file name needs to be specified\n\
in the same order the 'm' and 'f' flags are specified.\n\
jar cvfm classes.jar mymanifest -C foo/ .\n\
");
- exit(1);
+ exit(0);
+}
+
+static char *
+jt_strdup(s)
+ char *s;
+{
+ char *result = (char*)malloc(strlen(s) + 1);
+ if (result == (char*)0)
+ return (char*)0;
+ strcpy(result, s);
+ return result;
+}
+
+/* Convert "tar-style" first argument to a form expected by getopt.
+ This idea and the code comes from GNU tar. This can allocate a new
+ argument vector. This might leak some memory, but we don't care. */
+static void
+expand_options (int *argcp, char ***argvp)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+
+ if (argc > 1 && argv[1][0] != '-')
+ {
+ char buf[3];
+ char **new_argv;
+ int new_argc;
+ char *p;
+ char **in, **out;
+
+ buf[0] = '-';
+ buf[2] = '\0';
+
+ new_argc = argc - 1 + strlen (argv[1]);
+ new_argv = (char **) malloc (new_argc * sizeof (char *));
+ in = argv;
+ out = new_argv;
+
+ *out++ = *in++;
+ for (p = *in++; *p; ++p)
+ {
+ char *opt;
+ buf[1] = *p;
+ *out++ = jt_strdup (buf);
+ /* If the option takes an argument, move the next argument
+ to just after this option. */
+ opt = strchr (OPTION_STRING, *p);
+ if (opt && opt[1] == ':')
+ {
+ if (in < argv + argc)
+ *out++ = *in++;
+ else
+ {
+ fprintf(stderr, "%s: option `%s' requires an argument.\n",
+ argv[0], buf);
+ usage(argv[0]);
+ }
+ }
+ }
+
+ /* Copy remaining options. */
+ while (in < argv + argc)
+ *out++ = *in++;
+
+ *argcp = new_argc;
+ *argvp = new_argv;
+ }
}