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