maint: port to platforms lacking SIGPIPE
[gzip.git] / util.c
blob46bc89d687edaa8e30f503184811e60459d98866
1 /* util.c -- utility functions for gzip support
3 Copyright (C) 1997-1999, 2001-2002, 2006, 2009-2012 Free Software
4 Foundation, Inc.
5 Copyright (C) 1992-1993 Jean-loup Gailly
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21 #include <config.h>
22 #include <ctype.h>
23 #include <errno.h>
25 #include "tailor.h"
27 #include <limits.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <errno.h>
33 #include "gzip.h"
34 #include <xalloc.h>
36 #ifndef CHAR_BIT
37 # define CHAR_BIT 8
38 #endif
40 static int write_buffer (int, voidp, unsigned int);
42 static const ulg crc_32_tab[]; /* crc table, defined below */
44 /* ===========================================================================
45 * Copy input to output unchanged: zcat == cat with --force.
46 * IN assertion: insize bytes have already been read in inbuf and inptr bytes
47 * already processed or copied.
49 int copy(in, out)
50 int in, out; /* input and output file descriptors */
52 int got;
54 errno = 0;
55 while (insize > inptr) {
56 write_buf(out, (char*)inbuf + inptr, insize - inptr);
57 bytes_out += insize - inptr;
58 got = read_buffer (in, (char *) inbuf, INBUFSIZ);
59 if (got == -1)
60 read_error();
61 bytes_in += got;
62 insize = (unsigned)got;
63 inptr = 0;
65 return OK;
68 /* ===========================================================================
69 * Run a set of bytes through the crc shift register. If s is a NULL
70 * pointer, then initialize the crc shift register contents instead.
71 * Return the current crc in either case.
73 ulg updcrc(s, n)
74 uch *s; /* pointer to bytes to pump through */
75 unsigned n; /* number of bytes in s[] */
77 register ulg c; /* temporary variable */
79 static ulg crc = (ulg)0xffffffffL; /* shift register contents */
81 if (s == NULL) {
82 c = 0xffffffffL;
83 } else {
84 c = crc;
85 if (n) do {
86 c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
87 } while (--n);
89 crc = c;
90 return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
93 /* ===========================================================================
94 * Clear input and output buffers
96 void clear_bufs()
98 outcnt = 0;
99 insize = inptr = 0;
100 bytes_in = bytes_out = 0L;
103 /* ===========================================================================
104 * Fill the input buffer. This is called only when the buffer is empty.
106 int fill_inbuf(eof_ok)
107 int eof_ok; /* set if EOF acceptable as a result */
109 int len;
111 /* Read as much as possible */
112 insize = 0;
113 do {
114 len = read_buffer (ifd, (char *) inbuf + insize, INBUFSIZ - insize);
115 if (len == 0) break;
116 if (len == -1) {
117 read_error();
118 break;
120 insize += len;
121 } while (insize < INBUFSIZ);
123 if (insize == 0) {
124 if (eof_ok) return EOF;
125 flush_window();
126 errno = 0;
127 read_error();
129 bytes_in += (off_t)insize;
130 inptr = 1;
131 return inbuf[0];
134 /* Like the standard read function, except do not attempt to read more
135 than SSIZE_MAX bytes at a time. */
137 read_buffer (fd, buf, cnt)
138 int fd;
139 voidp buf;
140 unsigned int cnt;
142 if (INT_MAX < cnt)
143 cnt = INT_MAX;
144 return read (fd, buf, cnt);
147 /* Likewise for 'write'. */
148 static int
149 write_buffer (fd, buf, cnt)
150 int fd;
151 voidp buf;
152 unsigned int cnt;
154 if (INT_MAX < cnt)
155 cnt = INT_MAX;
156 return write (fd, buf, cnt);
159 /* ===========================================================================
160 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
161 * (used for the compressed data only)
163 void flush_outbuf()
165 if (outcnt == 0) return;
167 write_buf(ofd, (char *)outbuf, outcnt);
168 bytes_out += (off_t)outcnt;
169 outcnt = 0;
172 /* ===========================================================================
173 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
174 * (Used for the decompressed data only.)
176 void flush_window()
178 if (outcnt == 0) return;
179 updcrc(window, outcnt);
181 if (!test) {
182 write_buf(ofd, (char *)window, outcnt);
184 bytes_out += (off_t)outcnt;
185 outcnt = 0;
188 /* ===========================================================================
189 * Does the same as write(), but also handles partial pipe writes and checks
190 * for error return.
192 void write_buf(fd, buf, cnt)
193 int fd;
194 voidp buf;
195 unsigned cnt;
197 unsigned n;
199 while ((n = write_buffer (fd, buf, cnt)) != cnt) {
200 if (n == (unsigned)(-1)) {
201 write_error();
203 cnt -= n;
204 buf = (voidp)((char*)buf+n);
208 /* ========================================================================
209 * Put string s in lower case, return s.
211 char *strlwr(s)
212 char *s;
214 char *t;
215 for (t = s; *t; t++)
216 *t = tolow ((unsigned char) *t);
217 return s;
220 /* ========================================================================
221 * Return the base name of a file (remove any directory prefix and
222 * any version suffix). For systems with file names that are not
223 * case sensitive, force the base name to lower case.
225 char *
226 gzip_base_name (fname)
227 char *fname;
229 char *p;
231 if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1;
232 #ifdef PATH_SEP2
233 if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
234 #endif
235 #ifdef PATH_SEP3
236 if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
237 #endif
238 #ifdef SUFFIX_SEP
239 if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
240 #endif
241 if (casemap('A') == 'a') strlwr(fname);
242 return fname;
245 /* ========================================================================
246 * Unlink a file, working around the unlink readonly bug (if present).
248 int xunlink (filename)
249 char *filename;
251 int r = unlink (filename);
253 #ifdef UNLINK_READONLY_BUG
254 if (r != 0)
256 int e = errno;
257 if (chmod (filename, S_IWUSR) != 0)
259 errno = e;
260 return -1;
263 r = unlink (filename);
265 #endif
267 return r;
270 /* ========================================================================
271 * Make a file name legal for file systems not allowing file names with
272 * multiple dots or starting with a dot (such as MSDOS), by changing
273 * all dots except the last one into underlines. A target dependent
274 * function can be used instead of this simple function by defining the macro
275 * MAKE_LEGAL_NAME in tailor.h and providing the function in a target
276 * dependent module.
278 void make_simple_name(name)
279 char *name;
281 char *p = strrchr(name, '.');
282 if (p == NULL) return;
283 if (p == name) p++;
284 do {
285 if (*--p == '.') *p = '_';
286 } while (p != name);
289 /* ========================================================================
290 * Add an environment variable (if any) before argv, and update argc.
291 * Return the expanded environment variable to be freed later, or NULL
292 * if no options were added to argv.
294 #define SEPARATOR " \t" /* separators in env variable */
296 char *add_envopt(
297 int *argcp, /* pointer to argc */
298 char ***argvp, /* pointer to argv */
299 char const *envvar_name) /* name of environment variable */
301 char *p; /* running pointer through env variable */
302 char **oargv; /* runs through old argv array */
303 char **nargv; /* runs through new argv array */
304 int oargc = *argcp; /* old argc */
305 int nargc = 0; /* number of arguments in env variable */
306 char *env_val;
308 env_val = getenv(envvar_name);
309 if (env_val == NULL) return NULL;
311 env_val = xstrdup (env_val);
313 for (p = env_val; *p; nargc++ ) { /* move through env_val */
314 p += strspn(p, SEPARATOR); /* skip leading separators */
315 if (*p == '\0') break;
317 p += strcspn(p, SEPARATOR); /* find end of word */
318 if (*p) *p++ = '\0'; /* mark it */
320 if (nargc == 0) {
321 free(env_val);
322 return NULL;
324 *argcp += nargc;
325 /* Allocate the new argv array, with an extra element just in case
326 * the original arg list did not end with a NULL.
328 nargv = xcalloc (*argcp + 1, sizeof (char *));
329 oargv = *argvp;
330 *argvp = nargv;
332 /* Copy the program name first */
333 if (oargc-- < 0)
334 gzip_error ("argc<=0");
335 *(nargv++) = *(oargv++);
337 /* Then copy the environment args */
338 for (p = env_val; nargc > 0; nargc--) {
339 p += strspn(p, SEPARATOR); /* skip separators */
340 *(nargv++) = p; /* store start */
341 while (*p++) ; /* skip over word */
344 /* Finally copy the old args and add a NULL (usual convention) */
345 while (oargc--) *(nargv++) = *(oargv++);
346 *nargv = NULL;
347 return env_val;
350 /* ========================================================================
351 * Error handlers.
353 void
354 gzip_error (char const *m)
356 fprintf (stderr, "\n%s: %s: %s\n", program_name, ifname, m);
357 abort_gzip();
360 void
361 xalloc_die ()
363 fprintf (stderr, "\n%s: memory_exhausted\n", program_name);
364 abort_gzip ();
367 void warning (char const *m)
369 WARN ((stderr, "%s: %s: warning: %s\n", program_name, ifname, m));
372 void read_error()
374 int e = errno;
375 fprintf (stderr, "\n%s: ", program_name);
376 if (e != 0) {
377 errno = e;
378 perror(ifname);
379 } else {
380 fprintf(stderr, "%s: unexpected end of file\n", ifname);
382 abort_gzip();
385 void write_error()
387 int e = errno;
388 fprintf (stderr, "\n%s: ", program_name);
389 errno = e;
390 perror(ofname);
391 abort_gzip();
394 /* ========================================================================
395 * Display compression ratio on the given stream on 6 characters.
397 void display_ratio(num, den, file)
398 off_t num;
399 off_t den;
400 FILE *file;
402 fprintf(file, "%5.1f%%", den == 0 ? 0 : 100.0 * num / den);
405 /* ========================================================================
406 * Print an off_t. There's no completely portable way to use printf,
407 * so we do it ourselves.
409 void fprint_off(file, offset, width)
410 FILE *file;
411 off_t offset;
412 int width;
414 char buf[CHAR_BIT * sizeof (off_t)];
415 char *p = buf + sizeof buf;
417 /* Don't negate offset here; it might overflow. */
418 if (offset < 0) {
420 *--p = '0' - offset % 10;
421 while ((offset /= 10) != 0);
423 *--p = '-';
424 } else {
426 *--p = '0' + offset % 10;
427 while ((offset /= 10) != 0);
430 width -= buf + sizeof buf - p;
431 while (0 < width--) {
432 putc (' ', file);
434 for (; p < buf + sizeof buf; p++)
435 putc (*p, file);
438 /* ========================================================================
439 * Table of CRC-32's of all single-byte values (made by makecrc.c)
441 static const ulg crc_32_tab[] = {
442 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
443 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
444 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
445 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
446 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
447 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
448 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
449 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
450 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
451 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
452 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
453 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
454 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
455 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
456 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
457 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
458 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
459 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
460 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
461 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
462 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
463 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
464 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
465 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
466 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
467 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
468 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
469 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
470 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
471 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
472 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
473 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
474 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
475 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
476 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
477 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
478 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
479 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
480 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
481 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
482 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
483 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
484 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
485 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
486 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
487 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
488 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
489 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
490 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
491 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
492 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
493 0x2d02ef8dL