1230837Sdelphij/* minigzip.c -- simulate gzip using the zlib compression library
2230837Sdelphij * Copyright (C) 1995-2006, 2010, 2011 Jean-loup Gailly.
3230837Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h
4230837Sdelphij */
5230837Sdelphij
6230837Sdelphij/*
7230837Sdelphij * minigzip is a minimal implementation of the gzip utility. This is
8230837Sdelphij * only an example of using zlib and isn't meant to replace the
9230837Sdelphij * full-featured gzip. No attempt is made to deal with file systems
10230837Sdelphij * limiting names to 14 or 8+3 characters, etc... Error checking is
11230837Sdelphij * very limited. So use minigzip only for testing; use gzip for the
12230837Sdelphij * real thing. On MSDOS, use only on file names without extension
13230837Sdelphij * or in pipe mode.
14230837Sdelphij */
15230837Sdelphij
16230837Sdelphij/* @(#) $Id$ */
17230837Sdelphij
18230837Sdelphij#include "zlib.h"
19230837Sdelphij#include <stdio.h>
20230837Sdelphij
21230837Sdelphij#ifdef STDC
22230837Sdelphij#  include <string.h>
23230837Sdelphij#  include <stdlib.h>
24230837Sdelphij#endif
25230837Sdelphij
26230837Sdelphij#ifdef USE_MMAP
27230837Sdelphij#  include <sys/types.h>
28230837Sdelphij#  include <sys/mman.h>
29230837Sdelphij#  include <sys/stat.h>
30230837Sdelphij#endif
31230837Sdelphij
32230837Sdelphij#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
33230837Sdelphij#  include <fcntl.h>
34230837Sdelphij#  include <io.h>
35230837Sdelphij#  ifdef UNDER_CE
36230837Sdelphij#    include <stdlib.h>
37230837Sdelphij#  endif
38230837Sdelphij#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
39230837Sdelphij#else
40230837Sdelphij#  define SET_BINARY_MODE(file)
41230837Sdelphij#endif
42230837Sdelphij
43254069Sdelphij#ifdef _MSC_VER
44254069Sdelphij#  define snprintf _snprintf
45254069Sdelphij#endif
46254069Sdelphij
47230837Sdelphij#ifdef VMS
48230837Sdelphij#  define unlink delete
49230837Sdelphij#  define GZ_SUFFIX "-gz"
50230837Sdelphij#endif
51230837Sdelphij#ifdef RISCOS
52230837Sdelphij#  define unlink remove
53230837Sdelphij#  define GZ_SUFFIX "-gz"
54230837Sdelphij#  define fileno(file) file->__file
55230837Sdelphij#endif
56230837Sdelphij#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
57230837Sdelphij#  include <unix.h> /* for fileno */
58230837Sdelphij#endif
59230837Sdelphij
60230837Sdelphij#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE)
61230837Sdelphij#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
62230837Sdelphij  extern int unlink OF((const char *));
63230837Sdelphij#endif
64230837Sdelphij#endif
65230837Sdelphij
66230837Sdelphij#if defined(UNDER_CE)
67230837Sdelphij#  include <windows.h>
68230837Sdelphij#  define perror(s) pwinerror(s)
69230837Sdelphij
70230837Sdelphij/* Map the Windows error number in ERROR to a locale-dependent error
71230837Sdelphij   message string and return a pointer to it.  Typically, the values
72230837Sdelphij   for ERROR come from GetLastError.
73230837Sdelphij
74230837Sdelphij   The string pointed to shall not be modified by the application,
75230837Sdelphij   but may be overwritten by a subsequent call to strwinerror
76230837Sdelphij
77230837Sdelphij   The strwinerror function does not change the current setting
78230837Sdelphij   of GetLastError.  */
79230837Sdelphij
80230837Sdelphijstatic char *strwinerror (error)
81230837Sdelphij     DWORD error;
82230837Sdelphij{
83230837Sdelphij    static char buf[1024];
84230837Sdelphij
85230837Sdelphij    wchar_t *msgbuf;
86230837Sdelphij    DWORD lasterr = GetLastError();
87230837Sdelphij    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
88230837Sdelphij        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
89230837Sdelphij        NULL,
90230837Sdelphij        error,
91230837Sdelphij        0, /* Default language */
92230837Sdelphij        (LPVOID)&msgbuf,
93230837Sdelphij        0,
94230837Sdelphij        NULL);
95230837Sdelphij    if (chars != 0) {
96230837Sdelphij        /* If there is an \r\n appended, zap it.  */
97230837Sdelphij        if (chars >= 2
98230837Sdelphij            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
99230837Sdelphij            chars -= 2;
100230837Sdelphij            msgbuf[chars] = 0;
101230837Sdelphij        }
102230837Sdelphij
103230837Sdelphij        if (chars > sizeof (buf) - 1) {
104230837Sdelphij            chars = sizeof (buf) - 1;
105230837Sdelphij            msgbuf[chars] = 0;
106230837Sdelphij        }
107230837Sdelphij
108230837Sdelphij        wcstombs(buf, msgbuf, chars + 1);
109230837Sdelphij        LocalFree(msgbuf);
110230837Sdelphij    }
111230837Sdelphij    else {
112230837Sdelphij        sprintf(buf, "unknown win32 error (%ld)", error);
113230837Sdelphij    }
114230837Sdelphij
115230837Sdelphij    SetLastError(lasterr);
116230837Sdelphij    return buf;
117230837Sdelphij}
118230837Sdelphij
119230837Sdelphijstatic void pwinerror (s)
120230837Sdelphij    const char *s;
121230837Sdelphij{
122230837Sdelphij    if (s && *s)
123230837Sdelphij        fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
124230837Sdelphij    else
125230837Sdelphij        fprintf(stderr, "%s\n", strwinerror(GetLastError ()));
126230837Sdelphij}
127230837Sdelphij
128230837Sdelphij#endif /* UNDER_CE */
129230837Sdelphij
130230837Sdelphij#ifndef GZ_SUFFIX
131230837Sdelphij#  define GZ_SUFFIX ".gz"
132230837Sdelphij#endif
133230837Sdelphij#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
134230837Sdelphij
135230837Sdelphij#define BUFLEN      16384
136230837Sdelphij#define MAX_NAME_LEN 1024
137230837Sdelphij
138230837Sdelphij#ifdef MAXSEG_64K
139230837Sdelphij#  define local static
140230837Sdelphij   /* Needed for systems with limitation on stack size. */
141230837Sdelphij#else
142230837Sdelphij#  define local
143230837Sdelphij#endif
144230837Sdelphij
145230837Sdelphij#ifdef Z_SOLO
146230837Sdelphij/* for Z_SOLO, create simplified gz* functions using deflate and inflate */
147230837Sdelphij
148230837Sdelphij#if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE)
149230837Sdelphij#  include <unistd.h>       /* for unlink() */
150230837Sdelphij#endif
151230837Sdelphij
152230837Sdelphijvoid *myalloc OF((void *, unsigned, unsigned));
153230837Sdelphijvoid myfree OF((void *, void *));
154230837Sdelphij
155230837Sdelphijvoid *myalloc(q, n, m)
156230837Sdelphij    void *q;
157230837Sdelphij    unsigned n, m;
158230837Sdelphij{
159230837Sdelphij    q = Z_NULL;
160230837Sdelphij    return calloc(n, m);
161230837Sdelphij}
162230837Sdelphij
163230837Sdelphijvoid myfree(q, p)
164230837Sdelphij    void *q, *p;
165230837Sdelphij{
166230837Sdelphij    q = Z_NULL;
167230837Sdelphij    free(p);
168230837Sdelphij}
169230837Sdelphij
170230837Sdelphijtypedef struct gzFile_s {
171230837Sdelphij    FILE *file;
172230837Sdelphij    int write;
173230837Sdelphij    int err;
174230837Sdelphij    char *msg;
175230837Sdelphij    z_stream strm;
176230837Sdelphij} *gzFile;
177230837Sdelphij
178230837SdelphijgzFile gzopen OF((const char *, const char *));
179230837SdelphijgzFile gzdopen OF((int, const char *));
180230837SdelphijgzFile gz_open OF((const char *, int, const char *));
181230837Sdelphij
182230837SdelphijgzFile gzopen(path, mode)
183230837Sdelphijconst char *path;
184230837Sdelphijconst char *mode;
185230837Sdelphij{
186230837Sdelphij    return gz_open(path, -1, mode);
187230837Sdelphij}
188230837Sdelphij
189230837SdelphijgzFile gzdopen(fd, mode)
190230837Sdelphijint fd;
191230837Sdelphijconst char *mode;
192230837Sdelphij{
193230837Sdelphij    return gz_open(NULL, fd, mode);
194230837Sdelphij}
195230837Sdelphij
196230837SdelphijgzFile gz_open(path, fd, mode)
197230837Sdelphij    const char *path;
198230837Sdelphij    int fd;
199230837Sdelphij    const char *mode;
200230837Sdelphij{
201230837Sdelphij    gzFile gz;
202230837Sdelphij    int ret;
203230837Sdelphij
204237248Sdelphij    gz = malloc(sizeof(struct gzFile_s));
205230837Sdelphij    if (gz == NULL)
206230837Sdelphij        return NULL;
207230837Sdelphij    gz->write = strchr(mode, 'w') != NULL;
208230837Sdelphij    gz->strm.zalloc = myalloc;
209230837Sdelphij    gz->strm.zfree = myfree;
210230837Sdelphij    gz->strm.opaque = Z_NULL;
211230837Sdelphij    if (gz->write)
212230837Sdelphij        ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0);
213230837Sdelphij    else {
214230837Sdelphij        gz->strm.next_in = 0;
215230837Sdelphij        gz->strm.avail_in = Z_NULL;
216230837Sdelphij        ret = inflateInit2(&(gz->strm), 15 + 16);
217230837Sdelphij    }
218230837Sdelphij    if (ret != Z_OK) {
219230837Sdelphij        free(gz);
220230837Sdelphij        return NULL;
221230837Sdelphij    }
222230837Sdelphij    gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") :
223230837Sdelphij                              fopen(path, gz->write ? "wb" : "rb");
224230837Sdelphij    if (gz->file == NULL) {
225230837Sdelphij        gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm));
226230837Sdelphij        free(gz);
227230837Sdelphij        return NULL;
228230837Sdelphij    }
229230837Sdelphij    gz->err = 0;
230230837Sdelphij    gz->msg = "";
231230837Sdelphij    return gz;
232230837Sdelphij}
233230837Sdelphij
234230837Sdelphijint gzwrite OF((gzFile, const void *, unsigned));
235230837Sdelphij
236230837Sdelphijint gzwrite(gz, buf, len)
237230837Sdelphij    gzFile gz;
238230837Sdelphij    const void *buf;
239230837Sdelphij    unsigned len;
240230837Sdelphij{
241230837Sdelphij    z_stream *strm;
242230837Sdelphij    unsigned char out[BUFLEN];
243230837Sdelphij
244230837Sdelphij    if (gz == NULL || !gz->write)
245230837Sdelphij        return 0;
246230837Sdelphij    strm = &(gz->strm);
247230837Sdelphij    strm->next_in = (void *)buf;
248230837Sdelphij    strm->avail_in = len;
249230837Sdelphij    do {
250230837Sdelphij        strm->next_out = out;
251230837Sdelphij        strm->avail_out = BUFLEN;
252230837Sdelphij        (void)deflate(strm, Z_NO_FLUSH);
253230837Sdelphij        fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
254230837Sdelphij    } while (strm->avail_out == 0);
255230837Sdelphij    return len;
256230837Sdelphij}
257230837Sdelphij
258230837Sdelphijint gzread OF((gzFile, void *, unsigned));
259230837Sdelphij
260230837Sdelphijint gzread(gz, buf, len)
261230837Sdelphij    gzFile gz;
262230837Sdelphij    void *buf;
263230837Sdelphij    unsigned len;
264230837Sdelphij{
265230837Sdelphij    int ret;
266230837Sdelphij    unsigned got;
267230837Sdelphij    unsigned char in[1];
268230837Sdelphij    z_stream *strm;
269230837Sdelphij
270230837Sdelphij    if (gz == NULL || gz->write)
271230837Sdelphij        return 0;
272230837Sdelphij    if (gz->err)
273230837Sdelphij        return 0;
274230837Sdelphij    strm = &(gz->strm);
275230837Sdelphij    strm->next_out = (void *)buf;
276230837Sdelphij    strm->avail_out = len;
277230837Sdelphij    do {
278230837Sdelphij        got = fread(in, 1, 1, gz->file);
279230837Sdelphij        if (got == 0)
280230837Sdelphij            break;
281230837Sdelphij        strm->next_in = in;
282230837Sdelphij        strm->avail_in = 1;
283230837Sdelphij        ret = inflate(strm, Z_NO_FLUSH);
284230837Sdelphij        if (ret == Z_DATA_ERROR) {
285230837Sdelphij            gz->err = Z_DATA_ERROR;
286230837Sdelphij            gz->msg = strm->msg;
287230837Sdelphij            return 0;
288230837Sdelphij        }
289230837Sdelphij        if (ret == Z_STREAM_END)
290230837Sdelphij            inflateReset(strm);
291230837Sdelphij    } while (strm->avail_out);
292230837Sdelphij    return len - strm->avail_out;
293230837Sdelphij}
294230837Sdelphij
295230837Sdelphijint gzclose OF((gzFile));
296230837Sdelphij
297230837Sdelphijint gzclose(gz)
298230837Sdelphij    gzFile gz;
299230837Sdelphij{
300230837Sdelphij    z_stream *strm;
301230837Sdelphij    unsigned char out[BUFLEN];
302230837Sdelphij
303230837Sdelphij    if (gz == NULL)
304230837Sdelphij        return Z_STREAM_ERROR;
305230837Sdelphij    strm = &(gz->strm);
306230837Sdelphij    if (gz->write) {
307230837Sdelphij        strm->next_in = Z_NULL;
308230837Sdelphij        strm->avail_in = 0;
309230837Sdelphij        do {
310230837Sdelphij            strm->next_out = out;
311230837Sdelphij            strm->avail_out = BUFLEN;
312230837Sdelphij            (void)deflate(strm, Z_FINISH);
313230837Sdelphij            fwrite(out, 1, BUFLEN - strm->avail_out, gz->file);
314230837Sdelphij        } while (strm->avail_out == 0);
315230837Sdelphij        deflateEnd(strm);
316230837Sdelphij    }
317230837Sdelphij    else
318230837Sdelphij        inflateEnd(strm);
319230837Sdelphij    fclose(gz->file);
320230837Sdelphij    free(gz);
321230837Sdelphij    return Z_OK;
322230837Sdelphij}
323230837Sdelphij
324230837Sdelphijconst char *gzerror OF((gzFile, int *));
325230837Sdelphij
326230837Sdelphijconst char *gzerror(gz, err)
327230837Sdelphij    gzFile gz;
328230837Sdelphij    int *err;
329230837Sdelphij{
330230837Sdelphij    *err = gz->err;
331230837Sdelphij    return gz->msg;
332230837Sdelphij}
333230837Sdelphij
334230837Sdelphij#endif
335230837Sdelphij
336230837Sdelphijchar *prog;
337230837Sdelphij
338230837Sdelphijvoid error            OF((const char *msg));
339230837Sdelphijvoid gz_compress      OF((FILE   *in, gzFile out));
340230837Sdelphij#ifdef USE_MMAP
341230837Sdelphijint  gz_compress_mmap OF((FILE   *in, gzFile out));
342230837Sdelphij#endif
343230837Sdelphijvoid gz_uncompress    OF((gzFile in, FILE   *out));
344230837Sdelphijvoid file_compress    OF((char  *file, char *mode));
345230837Sdelphijvoid file_uncompress  OF((char  *file));
346230837Sdelphijint  main             OF((int argc, char *argv[]));
347230837Sdelphij
348230837Sdelphij/* ===========================================================================
349230837Sdelphij * Display error message and exit
350230837Sdelphij */
351230837Sdelphijvoid error(msg)
352230837Sdelphij    const char *msg;
353230837Sdelphij{
354230837Sdelphij    fprintf(stderr, "%s: %s\n", prog, msg);
355230837Sdelphij    exit(1);
356230837Sdelphij}
357230837Sdelphij
358230837Sdelphij/* ===========================================================================
359230837Sdelphij * Compress input to output then close both files.
360230837Sdelphij */
361230837Sdelphij
362230837Sdelphijvoid gz_compress(in, out)
363230837Sdelphij    FILE   *in;
364230837Sdelphij    gzFile out;
365230837Sdelphij{
366230837Sdelphij    local char buf[BUFLEN];
367230837Sdelphij    int len;
368230837Sdelphij    int err;
369230837Sdelphij
370230837Sdelphij#ifdef USE_MMAP
371230837Sdelphij    /* Try first compressing with mmap. If mmap fails (minigzip used in a
372230837Sdelphij     * pipe), use the normal fread loop.
373230837Sdelphij     */
374230837Sdelphij    if (gz_compress_mmap(in, out) == Z_OK) return;
375230837Sdelphij#endif
376230837Sdelphij    for (;;) {
377230837Sdelphij        len = (int)fread(buf, 1, sizeof(buf), in);
378230837Sdelphij        if (ferror(in)) {
379230837Sdelphij            perror("fread");
380230837Sdelphij            exit(1);
381230837Sdelphij        }
382230837Sdelphij        if (len == 0) break;
383230837Sdelphij
384230837Sdelphij        if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
385230837Sdelphij    }
386230837Sdelphij    fclose(in);
387230837Sdelphij    if (gzclose(out) != Z_OK) error("failed gzclose");
388230837Sdelphij}
389230837Sdelphij
390230837Sdelphij#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
391230837Sdelphij
392230837Sdelphij/* Try compressing the input file at once using mmap. Return Z_OK if
393230837Sdelphij * if success, Z_ERRNO otherwise.
394230837Sdelphij */
395230837Sdelphijint gz_compress_mmap(in, out)
396230837Sdelphij    FILE   *in;
397230837Sdelphij    gzFile out;
398230837Sdelphij{
399230837Sdelphij    int len;
400230837Sdelphij    int err;
401230837Sdelphij    int ifd = fileno(in);
402230837Sdelphij    caddr_t buf;    /* mmap'ed buffer for the entire input file */
403230837Sdelphij    off_t buf_len;  /* length of the input file */
404230837Sdelphij    struct stat sb;
405230837Sdelphij
406230837Sdelphij    /* Determine the size of the file, needed for mmap: */
407230837Sdelphij    if (fstat(ifd, &sb) < 0) return Z_ERRNO;
408230837Sdelphij    buf_len = sb.st_size;
409230837Sdelphij    if (buf_len <= 0) return Z_ERRNO;
410230837Sdelphij
411230837Sdelphij    /* Now do the actual mmap: */
412230837Sdelphij    buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
413230837Sdelphij    if (buf == (caddr_t)(-1)) return Z_ERRNO;
414230837Sdelphij
415230837Sdelphij    /* Compress the whole file at once: */
416230837Sdelphij    len = gzwrite(out, (char *)buf, (unsigned)buf_len);
417230837Sdelphij
418230837Sdelphij    if (len != (int)buf_len) error(gzerror(out, &err));
419230837Sdelphij
420230837Sdelphij    munmap(buf, buf_len);
421230837Sdelphij    fclose(in);
422230837Sdelphij    if (gzclose(out) != Z_OK) error("failed gzclose");
423230837Sdelphij    return Z_OK;
424230837Sdelphij}
425230837Sdelphij#endif /* USE_MMAP */
426230837Sdelphij
427230837Sdelphij/* ===========================================================================
428230837Sdelphij * Uncompress input to output then close both files.
429230837Sdelphij */
430230837Sdelphijvoid gz_uncompress(in, out)
431230837Sdelphij    gzFile in;
432230837Sdelphij    FILE   *out;
433230837Sdelphij{
434230837Sdelphij    local char buf[BUFLEN];
435230837Sdelphij    int len;
436230837Sdelphij    int err;
437230837Sdelphij
438230837Sdelphij    for (;;) {
439230837Sdelphij        len = gzread(in, buf, sizeof(buf));
440230837Sdelphij        if (len < 0) error (gzerror(in, &err));
441230837Sdelphij        if (len == 0) break;
442230837Sdelphij
443230837Sdelphij        if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
444230837Sdelphij            error("failed fwrite");
445230837Sdelphij        }
446230837Sdelphij    }
447230837Sdelphij    if (fclose(out)) error("failed fclose");
448230837Sdelphij
449230837Sdelphij    if (gzclose(in) != Z_OK) error("failed gzclose");
450230837Sdelphij}
451230837Sdelphij
452230837Sdelphij
453230837Sdelphij/* ===========================================================================
454230837Sdelphij * Compress the given file: create a corresponding .gz file and remove the
455230837Sdelphij * original.
456230837Sdelphij */
457230837Sdelphijvoid file_compress(file, mode)
458230837Sdelphij    char  *file;
459230837Sdelphij    char  *mode;
460230837Sdelphij{
461230837Sdelphij    local char outfile[MAX_NAME_LEN];
462230837Sdelphij    FILE  *in;
463230837Sdelphij    gzFile out;
464230837Sdelphij
465230837Sdelphij    if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) {
466230837Sdelphij        fprintf(stderr, "%s: filename too long\n", prog);
467230837Sdelphij        exit(1);
468230837Sdelphij    }
469230837Sdelphij
470254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
471254069Sdelphij    snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX);
472254069Sdelphij#else
473230837Sdelphij    strcpy(outfile, file);
474230837Sdelphij    strcat(outfile, GZ_SUFFIX);
475254069Sdelphij#endif
476230837Sdelphij
477230837Sdelphij    in = fopen(file, "rb");
478230837Sdelphij    if (in == NULL) {
479230837Sdelphij        perror(file);
480230837Sdelphij        exit(1);
481230837Sdelphij    }
482230837Sdelphij    out = gzopen(outfile, mode);
483230837Sdelphij    if (out == NULL) {
484230837Sdelphij        fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
485230837Sdelphij        exit(1);
486230837Sdelphij    }
487230837Sdelphij    gz_compress(in, out);
488230837Sdelphij
489230837Sdelphij    unlink(file);
490230837Sdelphij}
491230837Sdelphij
492230837Sdelphij
493230837Sdelphij/* ===========================================================================
494230837Sdelphij * Uncompress the given file and remove the original.
495230837Sdelphij */
496230837Sdelphijvoid file_uncompress(file)
497230837Sdelphij    char  *file;
498230837Sdelphij{
499230837Sdelphij    local char buf[MAX_NAME_LEN];
500230837Sdelphij    char *infile, *outfile;
501230837Sdelphij    FILE  *out;
502230837Sdelphij    gzFile in;
503230837Sdelphij    size_t len = strlen(file);
504230837Sdelphij
505230837Sdelphij    if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) {
506230837Sdelphij        fprintf(stderr, "%s: filename too long\n", prog);
507230837Sdelphij        exit(1);
508230837Sdelphij    }
509230837Sdelphij
510254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
511254069Sdelphij    snprintf(buf, sizeof(buf), "%s", file);
512254069Sdelphij#else
513230837Sdelphij    strcpy(buf, file);
514254069Sdelphij#endif
515230837Sdelphij
516230837Sdelphij    if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
517230837Sdelphij        infile = file;
518230837Sdelphij        outfile = buf;
519230837Sdelphij        outfile[len-3] = '\0';
520230837Sdelphij    } else {
521230837Sdelphij        outfile = file;
522230837Sdelphij        infile = buf;
523254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
524254069Sdelphij        snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX);
525254069Sdelphij#else
526230837Sdelphij        strcat(infile, GZ_SUFFIX);
527254069Sdelphij#endif
528230837Sdelphij    }
529230837Sdelphij    in = gzopen(infile, "rb");
530230837Sdelphij    if (in == NULL) {
531230837Sdelphij        fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
532230837Sdelphij        exit(1);
533230837Sdelphij    }
534230837Sdelphij    out = fopen(outfile, "wb");
535230837Sdelphij    if (out == NULL) {
536230837Sdelphij        perror(file);
537230837Sdelphij        exit(1);
538230837Sdelphij    }
539230837Sdelphij
540230837Sdelphij    gz_uncompress(in, out);
541230837Sdelphij
542230837Sdelphij    unlink(infile);
543230837Sdelphij}
544230837Sdelphij
545230837Sdelphij
546230837Sdelphij/* ===========================================================================
547230837Sdelphij * Usage:  minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...]
548230837Sdelphij *   -c : write to standard output
549230837Sdelphij *   -d : decompress
550230837Sdelphij *   -f : compress with Z_FILTERED
551230837Sdelphij *   -h : compress with Z_HUFFMAN_ONLY
552230837Sdelphij *   -r : compress with Z_RLE
553230837Sdelphij *   -1 to -9 : compression level
554230837Sdelphij */
555230837Sdelphij
556230837Sdelphijint main(argc, argv)
557230837Sdelphij    int argc;
558230837Sdelphij    char *argv[];
559230837Sdelphij{
560230837Sdelphij    int copyout = 0;
561230837Sdelphij    int uncompr = 0;
562230837Sdelphij    gzFile file;
563230837Sdelphij    char *bname, outmode[20];
564230837Sdelphij
565254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
566254069Sdelphij    snprintf(outmode, sizeof(outmode), "%s", "wb6 ");
567254069Sdelphij#else
568230837Sdelphij    strcpy(outmode, "wb6 ");
569254069Sdelphij#endif
570230837Sdelphij
571230837Sdelphij    prog = argv[0];
572230837Sdelphij    bname = strrchr(argv[0], '/');
573230837Sdelphij    if (bname)
574230837Sdelphij      bname++;
575230837Sdelphij    else
576230837Sdelphij      bname = argv[0];
577230837Sdelphij    argc--, argv++;
578230837Sdelphij
579230837Sdelphij    if (!strcmp(bname, "gunzip"))
580230837Sdelphij      uncompr = 1;
581230837Sdelphij    else if (!strcmp(bname, "zcat"))
582230837Sdelphij      copyout = uncompr = 1;
583230837Sdelphij
584230837Sdelphij    while (argc > 0) {
585230837Sdelphij      if (strcmp(*argv, "-c") == 0)
586230837Sdelphij        copyout = 1;
587230837Sdelphij      else if (strcmp(*argv, "-d") == 0)
588230837Sdelphij        uncompr = 1;
589230837Sdelphij      else if (strcmp(*argv, "-f") == 0)
590230837Sdelphij        outmode[3] = 'f';
591230837Sdelphij      else if (strcmp(*argv, "-h") == 0)
592230837Sdelphij        outmode[3] = 'h';
593230837Sdelphij      else if (strcmp(*argv, "-r") == 0)
594230837Sdelphij        outmode[3] = 'R';
595230837Sdelphij      else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
596230837Sdelphij               (*argv)[2] == 0)
597230837Sdelphij        outmode[2] = (*argv)[1];
598230837Sdelphij      else
599230837Sdelphij        break;
600230837Sdelphij      argc--, argv++;
601230837Sdelphij    }
602230837Sdelphij    if (outmode[3] == ' ')
603230837Sdelphij        outmode[3] = 0;
604230837Sdelphij    if (argc == 0) {
605230837Sdelphij        SET_BINARY_MODE(stdin);
606230837Sdelphij        SET_BINARY_MODE(stdout);
607230837Sdelphij        if (uncompr) {
608230837Sdelphij            file = gzdopen(fileno(stdin), "rb");
609230837Sdelphij            if (file == NULL) error("can't gzdopen stdin");
610230837Sdelphij            gz_uncompress(file, stdout);
611230837Sdelphij        } else {
612230837Sdelphij            file = gzdopen(fileno(stdout), outmode);
613230837Sdelphij            if (file == NULL) error("can't gzdopen stdout");
614230837Sdelphij            gz_compress(stdin, file);
615230837Sdelphij        }
616230837Sdelphij    } else {
617230837Sdelphij        if (copyout) {
618230837Sdelphij            SET_BINARY_MODE(stdout);
619230837Sdelphij        }
620230837Sdelphij        do {
621230837Sdelphij            if (uncompr) {
622230837Sdelphij                if (copyout) {
623230837Sdelphij                    file = gzopen(*argv, "rb");
624230837Sdelphij                    if (file == NULL)
625230837Sdelphij                        fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv);
626230837Sdelphij                    else
627230837Sdelphij                        gz_uncompress(file, stdout);
628230837Sdelphij                } else {
629230837Sdelphij                    file_uncompress(*argv);
630230837Sdelphij                }
631230837Sdelphij            } else {
632230837Sdelphij                if (copyout) {
633230837Sdelphij                    FILE * in = fopen(*argv, "rb");
634230837Sdelphij
635230837Sdelphij                    if (in == NULL) {
636230837Sdelphij                        perror(*argv);
637230837Sdelphij                    } else {
638230837Sdelphij                        file = gzdopen(fileno(stdout), outmode);
639230837Sdelphij                        if (file == NULL) error("can't gzdopen stdout");
640230837Sdelphij
641230837Sdelphij                        gz_compress(in, file);
642230837Sdelphij                    }
643230837Sdelphij
644230837Sdelphij                } else {
645230837Sdelphij                    file_compress(*argv, outmode);
646230837Sdelphij                }
647230837Sdelphij            }
648230837Sdelphij        } while (argv++, --argc);
649230837Sdelphij    }
650230837Sdelphij    return 0;
651230837Sdelphij}
652