1c3423655Schristos /* minigzip.c -- simulate gzip using the zlib compression library 2c3423655Schristos * Copyright (C) 1995-2006, 2010, 2011, 2016 Jean-loup Gailly 3c3423655Schristos * For conditions of distribution and use, see copyright notice in zlib.h 4c3423655Schristos */ 5c3423655Schristos 6c3423655Schristos /* 7c3423655Schristos * minigzip is a minimal implementation of the gzip utility. This is 8c3423655Schristos * only an example of using zlib and isn't meant to replace the 9c3423655Schristos * full-featured gzip. No attempt is made to deal with file systems 10c3423655Schristos * limiting names to 14 or 8+3 characters, etc... Error checking is 11c3423655Schristos * very limited. So use minigzip only for testing; use gzip for the 12c3423655Schristos * real thing. On MSDOS, use only on file names without extension 13c3423655Schristos * or in pipe mode. 14c3423655Schristos */ 15c3423655Schristos 16dbdd0313Schristos /* @(#) Id */ 17c3423655Schristos 18c3423655Schristos #include "zlib.h" 19c3423655Schristos #include <stdio.h> 20c3423655Schristos 21c3423655Schristos #ifdef STDC 22c3423655Schristos # include <string.h> 23c3423655Schristos # include <stdlib.h> 24c3423655Schristos #endif 25c3423655Schristos 26c3423655Schristos #ifdef USE_MMAP 27c3423655Schristos # include <sys/types.h> 28c3423655Schristos # include <sys/mman.h> 29c3423655Schristos # include <sys/stat.h> 30c3423655Schristos #endif 31c3423655Schristos 32c3423655Schristos #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) 33c3423655Schristos # include <fcntl.h> 34c3423655Schristos # include <io.h> 35c3423655Schristos # ifdef UNDER_CE 36c3423655Schristos # include <stdlib.h> 37c3423655Schristos # endif 38c3423655Schristos # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) 39c3423655Schristos #else 40c3423655Schristos # define SET_BINARY_MODE(file) 41c3423655Schristos #endif 42c3423655Schristos 43c3423655Schristos #if defined(_MSC_VER) && _MSC_VER < 1900 44c3423655Schristos # define snprintf _snprintf 45c3423655Schristos #endif 46c3423655Schristos 47c3423655Schristos #ifdef VMS 48c3423655Schristos # define unlink delete 49c3423655Schristos # define GZ_SUFFIX "-gz" 50c3423655Schristos #endif 51c3423655Schristos #ifdef RISCOS 52c3423655Schristos # define unlink remove 53c3423655Schristos # define GZ_SUFFIX "-gz" 54c3423655Schristos # define fileno(file) file->__file 55c3423655Schristos #endif 56c3423655Schristos #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os 57c3423655Schristos # include <unix.h> /* for fileno */ 58c3423655Schristos #endif 59c3423655Schristos 60c3423655Schristos #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) 61c3423655Schristos #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ 62*b175d1c2Schristos extern int unlink(const char *); 63c3423655Schristos #endif 64c3423655Schristos #endif 65c3423655Schristos 66c3423655Schristos #if defined(UNDER_CE) 67c3423655Schristos # include <windows.h> 68c3423655Schristos # define perror(s) pwinerror(s) 69c3423655Schristos 70c3423655Schristos /* Map the Windows error number in ERROR to a locale-dependent error 71c3423655Schristos message string and return a pointer to it. Typically, the values 72c3423655Schristos for ERROR come from GetLastError. 73c3423655Schristos 74c3423655Schristos The string pointed to shall not be modified by the application, 75c3423655Schristos but may be overwritten by a subsequent call to strwinerror 76c3423655Schristos 77c3423655Schristos The strwinerror function does not change the current setting 78c3423655Schristos of GetLastError. */ 79c3423655Schristos 80c3423655Schristos static char *strwinerror (error) 81c3423655Schristos DWORD error; 82c3423655Schristos { 83c3423655Schristos static char buf[1024]; 84c3423655Schristos 85c3423655Schristos wchar_t *msgbuf; 86c3423655Schristos DWORD lasterr = GetLastError(); 87c3423655Schristos DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM 88c3423655Schristos | FORMAT_MESSAGE_ALLOCATE_BUFFER, 89c3423655Schristos NULL, 90c3423655Schristos error, 91c3423655Schristos 0, /* Default language */ 92c3423655Schristos (LPVOID)&msgbuf, 93c3423655Schristos 0, 94c3423655Schristos NULL); 95c3423655Schristos if (chars != 0) { 96c3423655Schristos /* If there is an \r\n appended, zap it. */ 97c3423655Schristos if (chars >= 2 98c3423655Schristos && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { 99c3423655Schristos chars -= 2; 100c3423655Schristos msgbuf[chars] = 0; 101c3423655Schristos } 102c3423655Schristos 103c3423655Schristos if (chars > sizeof (buf) - 1) { 104c3423655Schristos chars = sizeof (buf) - 1; 105c3423655Schristos msgbuf[chars] = 0; 106c3423655Schristos } 107c3423655Schristos 108c3423655Schristos wcstombs(buf, msgbuf, chars + 1); 109c3423655Schristos LocalFree(msgbuf); 110c3423655Schristos } 111c3423655Schristos else { 112c3423655Schristos sprintf(buf, "unknown win32 error (%ld)", error); 113c3423655Schristos } 114c3423655Schristos 115c3423655Schristos SetLastError(lasterr); 116c3423655Schristos return buf; 117c3423655Schristos } 118c3423655Schristos 119c3423655Schristos static void pwinerror (s) 120c3423655Schristos const char *s; 121c3423655Schristos { 122c3423655Schristos if (s && *s) 123c3423655Schristos fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); 124c3423655Schristos else 125c3423655Schristos fprintf(stderr, "%s\n", strwinerror(GetLastError ())); 126c3423655Schristos } 127c3423655Schristos 128c3423655Schristos #endif /* UNDER_CE */ 129c3423655Schristos 130c3423655Schristos #ifndef GZ_SUFFIX 131c3423655Schristos # define GZ_SUFFIX ".gz" 132c3423655Schristos #endif 133c3423655Schristos #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) 134c3423655Schristos 135c3423655Schristos #define BUFLEN 16384 136c3423655Schristos #define MAX_NAME_LEN 1024 137c3423655Schristos 138c3423655Schristos #ifdef MAXSEG_64K 139c3423655Schristos # define local static 140c3423655Schristos /* Needed for systems with limitation on stack size. */ 141c3423655Schristos #else 142c3423655Schristos # define local 143c3423655Schristos #endif 144c3423655Schristos 145c3423655Schristos #ifdef Z_SOLO 146c3423655Schristos /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ 147c3423655Schristos 148c3423655Schristos #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) 149c3423655Schristos # include <unistd.h> /* for unlink() */ 150c3423655Schristos #endif 151c3423655Schristos 152*b175d1c2Schristos static void *myalloc(void *q, unsigned n, unsigned m) { 153c3423655Schristos (void)q; 154c3423655Schristos return calloc(n, m); 155c3423655Schristos } 156c3423655Schristos 157*b175d1c2Schristos static void myfree(void *q, void *p) { 158c3423655Schristos (void)q; 159c3423655Schristos free(p); 160c3423655Schristos } 161c3423655Schristos 162c3423655Schristos typedef struct gzFile_s { 163c3423655Schristos FILE *file; 164c3423655Schristos int write; 165c3423655Schristos int err; 166c3423655Schristos char *msg; 167c3423655Schristos z_stream strm; 168c3423655Schristos } *gzFile; 169c3423655Schristos 170*b175d1c2Schristos static gzFile gz_open(const char *path, int fd, const char *mode) { 171c3423655Schristos gzFile gz; 172c3423655Schristos int ret; 173c3423655Schristos 174c3423655Schristos gz = malloc(sizeof(struct gzFile_s)); 175c3423655Schristos if (gz == NULL) 176c3423655Schristos return NULL; 177c3423655Schristos gz->write = strchr(mode, 'w') != NULL; 178c3423655Schristos gz->strm.zalloc = myalloc; 179c3423655Schristos gz->strm.zfree = myfree; 180c3423655Schristos gz->strm.opaque = Z_NULL; 181c3423655Schristos if (gz->write) 182c3423655Schristos ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); 183c3423655Schristos else { 184c3423655Schristos gz->strm.next_in = 0; 185c3423655Schristos gz->strm.avail_in = Z_NULL; 186c3423655Schristos ret = inflateInit2(&(gz->strm), 15 + 16); 187c3423655Schristos } 188c3423655Schristos if (ret != Z_OK) { 189c3423655Schristos free(gz); 190c3423655Schristos return NULL; 191c3423655Schristos } 192c3423655Schristos gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : 193c3423655Schristos fopen(path, gz->write ? "wb" : "rb"); 194c3423655Schristos if (gz->file == NULL) { 195c3423655Schristos gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); 196c3423655Schristos free(gz); 197c3423655Schristos return NULL; 198c3423655Schristos } 199c3423655Schristos gz->err = 0; 200c3423655Schristos gz->msg = ""; 201c3423655Schristos return gz; 202c3423655Schristos } 203c3423655Schristos 204*b175d1c2Schristos static gzFile gzopen(const char *path, const char *mode) { 205*b175d1c2Schristos return gz_open(path, -1, mode); 206*b175d1c2Schristos } 207c3423655Schristos 208*b175d1c2Schristos static gzFile gzdopen(int fd, const char *mode) { 209*b175d1c2Schristos return gz_open(NULL, fd, mode); 210*b175d1c2Schristos } 211*b175d1c2Schristos 212*b175d1c2Schristos static int gzwrite(gzFile gz, const void *buf, unsigned len) { 213c3423655Schristos z_stream *strm; 214c3423655Schristos unsigned char out[BUFLEN]; 215c3423655Schristos 216c3423655Schristos if (gz == NULL || !gz->write) 217c3423655Schristos return 0; 218c3423655Schristos strm = &(gz->strm); 219c3423655Schristos strm->next_in = (void *)buf; 220c3423655Schristos strm->avail_in = len; 221c3423655Schristos do { 222c3423655Schristos strm->next_out = out; 223c3423655Schristos strm->avail_out = BUFLEN; 224c3423655Schristos (void)deflate(strm, Z_NO_FLUSH); 225c3423655Schristos fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); 226c3423655Schristos } while (strm->avail_out == 0); 227c3423655Schristos return len; 228c3423655Schristos } 229c3423655Schristos 230*b175d1c2Schristos static int gzread(gzFile gz, void *buf, unsigned len) { 231c3423655Schristos int ret; 232c3423655Schristos unsigned got; 233c3423655Schristos unsigned char in[1]; 234c3423655Schristos z_stream *strm; 235c3423655Schristos 236c3423655Schristos if (gz == NULL || gz->write) 237c3423655Schristos return 0; 238c3423655Schristos if (gz->err) 239c3423655Schristos return 0; 240c3423655Schristos strm = &(gz->strm); 241c3423655Schristos strm->next_out = (void *)buf; 242c3423655Schristos strm->avail_out = len; 243c3423655Schristos do { 244c3423655Schristos got = fread(in, 1, 1, gz->file); 245c3423655Schristos if (got == 0) 246c3423655Schristos break; 247c3423655Schristos strm->next_in = in; 248c3423655Schristos strm->avail_in = 1; 249c3423655Schristos ret = inflate(strm, Z_NO_FLUSH); 250c3423655Schristos if (ret == Z_DATA_ERROR) { 251c3423655Schristos gz->err = Z_DATA_ERROR; 252c3423655Schristos gz->msg = strm->msg; 253c3423655Schristos return 0; 254c3423655Schristos } 255c3423655Schristos if (ret == Z_STREAM_END) 256c3423655Schristos inflateReset(strm); 257c3423655Schristos } while (strm->avail_out); 258c3423655Schristos return len - strm->avail_out; 259c3423655Schristos } 260c3423655Schristos 261*b175d1c2Schristos static int gzclose(gzFile gz) { 262c3423655Schristos z_stream *strm; 263c3423655Schristos unsigned char out[BUFLEN]; 264c3423655Schristos 265c3423655Schristos if (gz == NULL) 266c3423655Schristos return Z_STREAM_ERROR; 267c3423655Schristos strm = &(gz->strm); 268c3423655Schristos if (gz->write) { 269c3423655Schristos strm->next_in = Z_NULL; 270c3423655Schristos strm->avail_in = 0; 271c3423655Schristos do { 272c3423655Schristos strm->next_out = out; 273c3423655Schristos strm->avail_out = BUFLEN; 274c3423655Schristos (void)deflate(strm, Z_FINISH); 275c3423655Schristos fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); 276c3423655Schristos } while (strm->avail_out == 0); 277c3423655Schristos deflateEnd(strm); 278c3423655Schristos } 279c3423655Schristos else 280c3423655Schristos inflateEnd(strm); 281c3423655Schristos fclose(gz->file); 282c3423655Schristos free(gz); 283c3423655Schristos return Z_OK; 284c3423655Schristos } 285c3423655Schristos 286*b175d1c2Schristos static const char *gzerror(gzFile gz, int *err) { 287c3423655Schristos *err = gz->err; 288c3423655Schristos return gz->msg; 289c3423655Schristos } 290c3423655Schristos 291c3423655Schristos #endif 292c3423655Schristos 293c3423655Schristos static char *prog; 294c3423655Schristos 295c3423655Schristos /* =========================================================================== 296c3423655Schristos * Display error message and exit 297c3423655Schristos */ 298*b175d1c2Schristos static void error(const char *msg) { 299c3423655Schristos fprintf(stderr, "%s: %s\n", prog, msg); 300c3423655Schristos exit(1); 301c3423655Schristos } 302c3423655Schristos 303c3423655Schristos #ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ 304c3423655Schristos 305c3423655Schristos /* Try compressing the input file at once using mmap. Return Z_OK if 306*b175d1c2Schristos * success, Z_ERRNO otherwise. 307c3423655Schristos */ 308*b175d1c2Schristos static int gz_compress_mmap(FILE *in, gzFile out) { 309c3423655Schristos int len; 310c3423655Schristos int err; 311c3423655Schristos int ifd = fileno(in); 312c3423655Schristos caddr_t buf; /* mmap'ed buffer for the entire input file */ 313c3423655Schristos off_t buf_len; /* length of the input file */ 314c3423655Schristos struct stat sb; 315c3423655Schristos 316c3423655Schristos /* Determine the size of the file, needed for mmap: */ 317c3423655Schristos if (fstat(ifd, &sb) < 0) return Z_ERRNO; 318c3423655Schristos buf_len = sb.st_size; 319c3423655Schristos if (buf_len <= 0) return Z_ERRNO; 320c3423655Schristos 321c3423655Schristos /* Now do the actual mmap: */ 322c3423655Schristos buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); 323c3423655Schristos if (buf == (caddr_t)(-1)) return Z_ERRNO; 324c3423655Schristos 325c3423655Schristos /* Compress the whole file at once: */ 326c3423655Schristos len = gzwrite(out, (char *)buf, (unsigned)buf_len); 327c3423655Schristos 328c3423655Schristos if (len != (int)buf_len) error(gzerror(out, &err)); 329c3423655Schristos 330c3423655Schristos munmap(buf, buf_len); 331c3423655Schristos fclose(in); 332c3423655Schristos if (gzclose(out) != Z_OK) error("failed gzclose"); 333c3423655Schristos return Z_OK; 334c3423655Schristos } 335c3423655Schristos #endif /* USE_MMAP */ 336c3423655Schristos 337c3423655Schristos /* =========================================================================== 338*b175d1c2Schristos * Compress input to output then close both files. 339*b175d1c2Schristos */ 340*b175d1c2Schristos 341*b175d1c2Schristos static void gz_compress(FILE *in, gzFile out) { 342*b175d1c2Schristos local char buf[BUFLEN]; 343*b175d1c2Schristos int len; 344*b175d1c2Schristos int err; 345*b175d1c2Schristos 346*b175d1c2Schristos #ifdef USE_MMAP 347*b175d1c2Schristos /* Try first compressing with mmap. If mmap fails (minigzip used in a 348*b175d1c2Schristos * pipe), use the normal fread loop. 349*b175d1c2Schristos */ 350*b175d1c2Schristos if (gz_compress_mmap(in, out) == Z_OK) return; 351*b175d1c2Schristos #endif 352*b175d1c2Schristos for (;;) { 353*b175d1c2Schristos len = (int)fread(buf, 1, sizeof(buf), in); 354*b175d1c2Schristos if (ferror(in)) { 355*b175d1c2Schristos perror("fread"); 356*b175d1c2Schristos exit(1); 357*b175d1c2Schristos } 358*b175d1c2Schristos if (len == 0) break; 359*b175d1c2Schristos 360*b175d1c2Schristos if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); 361*b175d1c2Schristos } 362*b175d1c2Schristos fclose(in); 363*b175d1c2Schristos if (gzclose(out) != Z_OK) error("failed gzclose"); 364*b175d1c2Schristos } 365*b175d1c2Schristos 366*b175d1c2Schristos /* =========================================================================== 367c3423655Schristos * Uncompress input to output then close both files. 368c3423655Schristos */ 369*b175d1c2Schristos static void gz_uncompress(gzFile in, FILE *out) { 370c3423655Schristos local char buf[BUFLEN]; 371c3423655Schristos int len; 372c3423655Schristos int err; 373c3423655Schristos 374c3423655Schristos for (;;) { 375c3423655Schristos len = gzread(in, buf, sizeof(buf)); 376c3423655Schristos if (len < 0) error (gzerror(in, &err)); 377c3423655Schristos if (len == 0) break; 378c3423655Schristos 379c3423655Schristos if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { 380c3423655Schristos error("failed fwrite"); 381c3423655Schristos } 382c3423655Schristos } 383c3423655Schristos if (fclose(out)) error("failed fclose"); 384c3423655Schristos 385c3423655Schristos if (gzclose(in) != Z_OK) error("failed gzclose"); 386c3423655Schristos } 387c3423655Schristos 388c3423655Schristos 389c3423655Schristos /* =========================================================================== 390c3423655Schristos * Compress the given file: create a corresponding .gz file and remove the 391c3423655Schristos * original. 392c3423655Schristos */ 393*b175d1c2Schristos static void file_compress(char *file, char *mode) { 394c3423655Schristos local char outfile[MAX_NAME_LEN]; 395c3423655Schristos FILE *in; 396c3423655Schristos gzFile out; 397c3423655Schristos 398c3423655Schristos if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { 399c3423655Schristos fprintf(stderr, "%s: filename too long\n", prog); 400c3423655Schristos exit(1); 401c3423655Schristos } 402c3423655Schristos 403c3423655Schristos #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 404c3423655Schristos snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); 405c3423655Schristos #else 406c3423655Schristos strcpy(outfile, file); 407c3423655Schristos strcat(outfile, GZ_SUFFIX); 408c3423655Schristos #endif 409c3423655Schristos 410c3423655Schristos in = fopen(file, "rb"); 411c3423655Schristos if (in == NULL) { 412c3423655Schristos perror(file); 413c3423655Schristos exit(1); 414c3423655Schristos } 415c3423655Schristos out = gzopen(outfile, mode); 416c3423655Schristos if (out == NULL) { 417c3423655Schristos fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); 418c3423655Schristos exit(1); 419c3423655Schristos } 420c3423655Schristos gz_compress(in, out); 421c3423655Schristos 422c3423655Schristos unlink(file); 423c3423655Schristos } 424c3423655Schristos 425c3423655Schristos 426c3423655Schristos /* =========================================================================== 427c3423655Schristos * Uncompress the given file and remove the original. 428c3423655Schristos */ 429*b175d1c2Schristos static void file_uncompress(char *file) { 430c3423655Schristos local char buf[MAX_NAME_LEN]; 431c3423655Schristos char *infile, *outfile; 432c3423655Schristos FILE *out; 433c3423655Schristos gzFile in; 434ec47cc4bSchristos z_size_t len = strlen(file); 435c3423655Schristos 436c3423655Schristos if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { 437c3423655Schristos fprintf(stderr, "%s: filename too long\n", prog); 438c3423655Schristos exit(1); 439c3423655Schristos } 440c3423655Schristos 441c3423655Schristos #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 442c3423655Schristos snprintf(buf, sizeof(buf), "%s", file); 443c3423655Schristos #else 444c3423655Schristos strcpy(buf, file); 445c3423655Schristos #endif 446c3423655Schristos 447c3423655Schristos if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { 448c3423655Schristos infile = file; 449c3423655Schristos outfile = buf; 450c3423655Schristos outfile[len-3] = '\0'; 451c3423655Schristos } else { 452c3423655Schristos outfile = file; 453c3423655Schristos infile = buf; 454c3423655Schristos #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 455c3423655Schristos snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); 456c3423655Schristos #else 457c3423655Schristos strcat(infile, GZ_SUFFIX); 458c3423655Schristos #endif 459c3423655Schristos } 460c3423655Schristos in = gzopen(infile, "rb"); 461c3423655Schristos if (in == NULL) { 462c3423655Schristos fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); 463c3423655Schristos exit(1); 464c3423655Schristos } 465c3423655Schristos out = fopen(outfile, "wb"); 466c3423655Schristos if (out == NULL) { 467c3423655Schristos perror(file); 468c3423655Schristos exit(1); 469c3423655Schristos } 470c3423655Schristos 471c3423655Schristos gz_uncompress(in, out); 472c3423655Schristos 473c3423655Schristos unlink(infile); 474c3423655Schristos } 475c3423655Schristos 476c3423655Schristos 477c3423655Schristos /* =========================================================================== 478c3423655Schristos * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] 479c3423655Schristos * -c : write to standard output 480c3423655Schristos * -d : decompress 481c3423655Schristos * -f : compress with Z_FILTERED 482c3423655Schristos * -h : compress with Z_HUFFMAN_ONLY 483c3423655Schristos * -r : compress with Z_RLE 484c3423655Schristos * -1 to -9 : compression level 485c3423655Schristos */ 486c3423655Schristos 487*b175d1c2Schristos int main(int argc, char *argv[]) { 488c3423655Schristos int copyout = 0; 489c3423655Schristos int uncompr = 0; 490c3423655Schristos gzFile file; 491c3423655Schristos char *bname, outmode[20]; 492c3423655Schristos 493c3423655Schristos #if !defined(NO_snprintf) && !defined(NO_vsnprintf) 494c3423655Schristos snprintf(outmode, sizeof(outmode), "%s", "wb6 "); 495c3423655Schristos #else 496c3423655Schristos strcpy(outmode, "wb6 "); 497c3423655Schristos #endif 498c3423655Schristos 499c3423655Schristos prog = argv[0]; 500c3423655Schristos bname = strrchr(argv[0], '/'); 501c3423655Schristos if (bname) 502c3423655Schristos bname++; 503c3423655Schristos else 504c3423655Schristos bname = argv[0]; 505c3423655Schristos argc--, argv++; 506c3423655Schristos 507c3423655Schristos if (!strcmp(bname, "gunzip")) 508c3423655Schristos uncompr = 1; 509c3423655Schristos else if (!strcmp(bname, "zcat")) 510c3423655Schristos copyout = uncompr = 1; 511c3423655Schristos 512c3423655Schristos while (argc > 0) { 513c3423655Schristos if (strcmp(*argv, "-c") == 0) 514c3423655Schristos copyout = 1; 515c3423655Schristos else if (strcmp(*argv, "-d") == 0) 516c3423655Schristos uncompr = 1; 517c3423655Schristos else if (strcmp(*argv, "-f") == 0) 518c3423655Schristos outmode[3] = 'f'; 519c3423655Schristos else if (strcmp(*argv, "-h") == 0) 520c3423655Schristos outmode[3] = 'h'; 521c3423655Schristos else if (strcmp(*argv, "-r") == 0) 522c3423655Schristos outmode[3] = 'R'; 523c3423655Schristos else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && 524c3423655Schristos (*argv)[2] == 0) 525c3423655Schristos outmode[2] = (*argv)[1]; 526c3423655Schristos else 527c3423655Schristos break; 528c3423655Schristos argc--, argv++; 529c3423655Schristos } 530c3423655Schristos if (outmode[3] == ' ') 531c3423655Schristos outmode[3] = 0; 532c3423655Schristos if (argc == 0) { 533c3423655Schristos SET_BINARY_MODE(stdin); 534c3423655Schristos SET_BINARY_MODE(stdout); 535c3423655Schristos if (uncompr) { 536c3423655Schristos file = gzdopen(fileno(stdin), "rb"); 537c3423655Schristos if (file == NULL) error("can't gzdopen stdin"); 538c3423655Schristos gz_uncompress(file, stdout); 539c3423655Schristos } else { 540c3423655Schristos file = gzdopen(fileno(stdout), outmode); 541c3423655Schristos if (file == NULL) error("can't gzdopen stdout"); 542c3423655Schristos gz_compress(stdin, file); 543c3423655Schristos } 544c3423655Schristos } else { 545c3423655Schristos if (copyout) { 546c3423655Schristos SET_BINARY_MODE(stdout); 547c3423655Schristos } 548c3423655Schristos do { 549c3423655Schristos if (uncompr) { 550c3423655Schristos if (copyout) { 551c3423655Schristos file = gzopen(*argv, "rb"); 552c3423655Schristos if (file == NULL) 553c3423655Schristos fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); 554c3423655Schristos else 555c3423655Schristos gz_uncompress(file, stdout); 556c3423655Schristos } else { 557c3423655Schristos file_uncompress(*argv); 558c3423655Schristos } 559c3423655Schristos } else { 560c3423655Schristos if (copyout) { 561c3423655Schristos FILE * in = fopen(*argv, "rb"); 562c3423655Schristos 563c3423655Schristos if (in == NULL) { 564c3423655Schristos perror(*argv); 565c3423655Schristos } else { 566c3423655Schristos file = gzdopen(fileno(stdout), outmode); 567c3423655Schristos if (file == NULL) error("can't gzdopen stdout"); 568c3423655Schristos 569c3423655Schristos gz_compress(in, file); 570c3423655Schristos } 571c3423655Schristos 572c3423655Schristos } else { 573c3423655Schristos file_compress(*argv, outmode); 574c3423655Schristos } 575c3423655Schristos } 576c3423655Schristos } while (argv++, --argc); 577c3423655Schristos } 578c3423655Schristos return 0; 579c3423655Schristos } 580