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