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