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
8static char rcsid[] = "$Id: util.c 3476 2003-06-11 15:56:10Z darkwyrm $";
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
33extern 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 */
39int 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 */
60ulg 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 */
83void 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 */
93int 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 */
120void 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 */
133void 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 */
149void 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 */
168char *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 */
181char *our_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 */
208void 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
228int strspn  OF((const char *s, const char *accept));
229int 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 */
235int 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 */
257int 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
279char *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 */
336void error(m)
337    char *m;
338{
339    fprintf(stderr, "\n%s: %s: %s\n", progname, ifname, m);
340    abort_gzip();
341}
342
343void warn(a, b)
344    char *a, *b;            /* message strings juxtaposed in output */
345{
346    WARN((stderr, "%s: %s: warning: %s%s\n", progname, ifname, a, b));
347}
348
349void read_error()
350{
351    fprintf(stderr, "\n%s: ", progname);
352    if (errno != 0) {
353	perror(ifname);
354    } else {
355	fprintf(stderr, "%s: unexpected end of file\n", ifname);
356    }
357    abort_gzip();
358}
359
360void write_error()
361{
362    fprintf(stderr, "\n%s: ", progname);
363    perror(ofname);
364    abort_gzip();
365}
366
367/* ========================================================================
368 * Display compression ratio on the given stream on 6 characters.
369 */
370void display_ratio(num, den, file)
371    long num;
372    long den;
373    FILE *file;
374{
375    long ratio;  /* 1000 times the compression ratio */
376
377    if (den == 0) {
378	ratio = 0; /* no compression */
379    } else if (den < 2147483L) { /* (2**31 -1)/1000 */
380	ratio = 1000L*num/den;
381    } else {
382	ratio = num/(den/1000L);
383    }
384    if (ratio < 0) {
385	putc('-', file);
386	ratio = -ratio;
387    } else {
388	putc(' ', file);
389    }
390    fprintf(file, "%2ld.%1ld%%", ratio / 10L, ratio % 10L);
391}
392
393
394/* ========================================================================
395 * Semi-safe malloc -- never returns NULL.
396 */
397voidp xmalloc (size)
398    unsigned size;
399{
400    voidp cp = (voidp)malloc (size);
401
402    if (cp == NULL) error("out of memory");
403    return cp;
404}
405
406/* ========================================================================
407 * Table of CRC-32's of all single-byte values (made by makecrc.c)
408 */
409ulg crc_32_tab[] = {
410  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
411  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
412  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
413  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
414  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
415  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
416  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
417  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
418  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
419  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
420  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
421  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
422  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
423  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
424  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
425  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
426  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
427  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
428  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
429  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
430  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
431  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
432  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
433  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
434  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
435  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
436  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
437  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
438  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
439  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
440  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
441  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
442  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
443  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
444  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
445  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
446  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
447  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
448  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
449  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
450  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
451  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
452  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
453  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
454  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
455  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
456  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
457  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
458  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
459  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
460  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
461  0x2d02ef8dL
462};
463