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