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