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