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