This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / gnu / usr.bin / gzip / util.c
CommitLineData
3013fe88
NW
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
e32dd11d 7#ifdef RCSID
caed0dfe 8static char rcsid[] = "$Id: util.c,v 0.15 1993/06/15 09:04:13 jloup Exp $";
3013fe88
NW
9#endif
10
3013fe88
NW
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
caed0dfe
NW
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
3013fe88
NW
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/* ===========================================================================
caed0dfe 91 * Fill the input buffer. This is called only when the buffer is empty.
3013fe88 92 */
caed0dfe
NW
93int fill_inbuf(eof_ok)
94 int eof_ok; /* set if EOF acceptable as a result */
3013fe88
NW
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) {
caed0dfe 108 if (eof_ok) return EOF;
3013fe88
NW
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 *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
caed0dfe
NW
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
3013fe88
NW
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) {
e32dd11d 304 free(env);
3013fe88
NW
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/* ========================================================================
caed0dfe 368 * Display compression ratio on the given stream on 6 characters.
3013fe88 369 */
caed0dfe 370void display_ratio(num, den, file)
3013fe88
NW
371 long num;
372 long den;
caed0dfe 373 FILE *file;
3013fe88
NW
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) {
caed0dfe 385 putc('-', file);
3013fe88 386 ratio = -ratio;
caed0dfe
NW
387 } else {
388 putc(' ', file);
3013fe88 389 }
caed0dfe 390 fprintf(file, "%2ld.%1ld%%", ratio / 10L, ratio % 10L);
3013fe88
NW
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};