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