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