Add README
[xapian-trec.git] / util.c
blob4c010475f3b1f0d768485ffa6a8b0ddb731b4a2d
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 */
7 #ifdef RCSID
8 static char rcsid[] = "$Id: util.c,v 0.15 1993/06/15 09:04:13 jloup Exp $";
9 #endif
11 #include <ctype.h>
12 #include <errno.h>
13 #include <sys/types.h>
15 #include "tailor.h"
17 # include <unistd.h>
18 # include <fcntl.h>
20 # include <stdlib.h>
22 #include "gzip.h"
23 #include "crypt.h"
25 extern ulg crc_32_tab[]; /* crc table, defined below */
27 /* ===========================================================================
28 * Copy input to output unchanged: zcat == cat with --force.
29 * IN assertion: insize bytes have already been read in inbuf.
31 int copy(in, out)
32 int in, out; /* input and output file descriptors */
34 errno = 0;
35 while (insize != 0 && (int)insize != EOF) {
36 write_buf(out, (char*)inbuf, insize);
37 bytes_out += insize;
38 insize = read(in, (char*)inbuf, INBUFSIZ);
40 if ((int)insize == EOF && errno != 0) {
41 read_error();
43 bytes_in = bytes_out;
44 return OK;
47 /* ===========================================================================
48 * Run a set of bytes through the crc shift register. If s is a NULL
49 * pointer, then initialize the crc shift register contents instead.
50 * Return the current crc in either case.
52 ulg updcrc(s, n)
53 uch *s; /* pointer to bytes to pump through */
54 unsigned n; /* number of bytes in s[] */
56 register ulg c; /* temporary variable */
58 static ulg crc = (ulg)0xffffffffL; /* shift register contents */
60 if (s == NULL) {
61 c = 0xffffffffL;
62 } else {
63 c = crc;
64 if (n) do {
65 c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
66 } while (--n);
68 crc = c;
69 return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
72 /* ===========================================================================
73 * Clear input and output buffers
75 void clear_bufs()
77 outcnt = 0;
78 outbufptr = 0;
79 insize = inptr = 0;
80 bytes_in = bytes_out = 0L;
83 /* ===========================================================================
84 * Fill the input buffer. This is called only when the buffer is empty.
86 int fill_inbuf(eof_ok)
87 int eof_ok; /* set if EOF acceptable as a result */
89 int len;
91 /* Read as much as possible */
92 insize = 0;
93 errno = 0;
94 do {
95 len = read(ifd, (char*)inbuf+insize, INBUFSIZ-insize);
96 if (len == 0 || len == EOF) break;
97 insize += len;
98 } while (insize < INBUFSIZ);
100 if (insize == 0) {
101 if (eof_ok) return EOF;
102 read_error();
104 bytes_in += (ulg)insize;
105 inptr = 1;
106 return inbuf[0];
109 /* ===========================================================================
110 * Write the output buffer outbuf[0..outcnt-1] and update bytes_out.
111 * (used for the compressed data only)
113 void flush_outbuf()
115 /* In PADRE, this is a NOOP, because the output buffer is never emptied */
116 return;
118 if (outcnt == 0) return;
120 write_buf(ofd, (char *)outbuf, outbufptr);
121 bytes_out += (ulg)outbufptr;
122 outbufptr = 0;
125 /* ===========================================================================
126 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
127 * (Used for the decompressed data only.)
129 void flush_window()
131 if (outcnt == 0) return;
132 updcrc(window, outcnt);
134 if (!test) {
135 write_buf(ofd, (char *)window, outcnt);
137 bytes_out += (ulg)outcnt;
138 outcnt = 0;
141 /* ===========================================================================
142 * Does the same as write(), but also handles partial pipe writes and checks
143 * for error return. NOT ANY MORE!
145 void write_buf(fd, buf, cnt)
146 int fd;
147 voidp buf;
148 unsigned cnt;
150 unsigned n;
152 if ((outbufptr + cnt) > outbuflen) {
153 fprintf(stderr, "Error: Decompressed file too big %d + %d\n",
154 outcnt, cnt);
155 exit_code = ERROR;
156 return;
157 } else {
158 memcpy(outbuf+outbufptr, buf, cnt);
159 outbufptr += cnt;
163 /* ========================================================================
164 * Put string s in lower case, return s.
166 char *strlwr(s)
167 char *s;
169 char *t;
170 for (t = s; *t; t++) *t = tolow(*t);
171 return s;
174 /* ========================================================================
175 * Return the base name of a file (remove any directory prefix and
176 * any version suffix). For systems with file names that are not
177 * case sensitive, force the base name to lower case.
179 char *basename(fname)
180 char *fname;
182 char *p;
184 if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1;
185 #ifdef PATH_SEP2
186 if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1;
187 #endif
188 #ifdef PATH_SEP3
189 if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1;
190 #endif
191 #ifdef SUFFIX_SEP
192 if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0';
193 #endif
194 if (casemap('A') == 'a') strlwr(fname);
195 return fname;
198 /* ========================================================================
199 * Make a file name legal for file systems not allowing file names with
200 * multiple dots or starting with a dot (such as MSDOS), by changing
201 * all dots except the last one into underlines. A target dependent
202 * function can be used instead of this simple function by defining the macro
203 * MAKE_LEGAL_NAME in tailor.h and providing the function in a target
204 * dependent module.
206 void make_simple_name(name)
207 char *name;
209 char *p = strrchr(name, '.');
210 if (p == NULL) return;
211 if (p == name) p++;
212 do {
213 if (*--p == '.') *p = '_';
214 } while (p != name);
218 #if defined(NO_STRING_H) && !defined(STDC_HEADERS)
220 /* Provide missing strspn and strcspn functions. */
222 # ifndef __STDC__
223 # define const
224 # endif
226 int strspn OF((const char *s, const char *accept));
227 int strcspn OF((const char *s, const char *reject));
229 /* ========================================================================
230 * Return the length of the maximum initial segment
231 * of s which contains only characters in accept.
233 int strspn(s, accept)
234 const char *s;
235 const char *accept;
237 register const char *p;
238 register const char *a;
239 register int count = 0;
241 for (p = s; *p != '\0'; ++p) {
242 for (a = accept; *a != '\0'; ++a) {
243 if (*p == *a) break;
245 if (*a == '\0') return count;
246 ++count;
248 return count;
251 /* ========================================================================
252 * Return the length of the maximum inital segment of s
253 * which contains no characters from reject.
255 int strcspn(s, reject)
256 const char *s;
257 const char *reject;
259 register int count = 0;
261 while (*s != '\0') {
262 if (strchr(reject, *s++) != NULL) return count;
263 ++count;
265 return count;
268 #endif /* NO_STRING_H */
270 /* ========================================================================
271 * Add an environment variable (if any) before argv, and update argc.
272 * Return the expanded environment variable to be freed later, or NULL
273 * if no options were added to argv.
275 #define SEPARATOR " \t" /* separators in env variable */
277 char *add_envopt(argcp, argvp, env)
278 int *argcp; /* pointer to argc */
279 char ***argvp; /* pointer to argv */
280 char *env; /* name of environment variable */
282 char *p; /* running pointer through env variable */
283 char **oargv; /* runs through old argv array */
284 char **nargv; /* runs through new argv array */
285 int oargc = *argcp; /* old argc */
286 int nargc = 0; /* number of arguments in env variable */
288 env = (char*)getenv(env);
289 if (env == NULL) return NULL;
291 p = (char*)xmalloc(strlen(env)+1);
292 env = strcpy(p, env); /* keep env variable intact */
294 for (p = env; *p; nargc++ ) { /* move through env */
295 p += strspn(p, SEPARATOR); /* skip leading separators */
296 if (*p == '\0') break;
298 p += strcspn(p, SEPARATOR); /* find end of word */
299 if (*p) *p++ = '\0'; /* mark it */
301 if (nargc == 0) {
302 free(env);
303 return NULL;
305 *argcp += nargc;
306 /* Allocate the new argv array, with an extra element just in case
307 * the original arg list did not end with a NULL.
309 nargv = (char**)calloc(*argcp+1, sizeof(char *));
310 if (nargv == NULL) error("out of memory");
311 oargv = *argvp;
312 *argvp = nargv;
314 /* Copy the program name first */
315 if (oargc-- < 0) error("argc<=0");
316 *(nargv++) = *(oargv++);
318 /* Then copy the environment args */
319 for (p = env; nargc > 0; nargc--) {
320 p += strspn(p, SEPARATOR); /* skip separators */
321 *(nargv++) = p; /* store start */
322 while (*p++) ; /* skip over word */
325 /* Finally copy the old args and add a NULL (usual convention) */
326 while (oargc--) *(nargv++) = *(oargv++);
327 *nargv = NULL;
328 return env;
331 /* ========================================================================
332 * Error handlers.
334 void error(m)
335 char *m;
337 fprintf(stderr, "Error: Damnation!\n");
338 return;
339 fprintf(stderr, "\n%s: %s: %s\n", progname, ifname, m);
340 /* abort_gzip(); */
343 void warn(a, b)
344 char *a, *b; /* message strings juxtaposed in output */
346 WARN((stderr, "%s: %s: warning: %s%s\n", progname, ifname, a, b));
349 void read_error()
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);
357 /* abort_gzip(); */
360 void write_error()
362 fprintf(stderr, "\n%s: ", progname);
363 perror(ofname);
364 /* abort_gzip(); */
367 /* ========================================================================
368 * Display compression ratio on the given stream on 6 characters.
370 void display_ratio(num, den, file)
371 long num;
372 long den;
373 FILE *file;
375 long ratio; /* 1000 times the compression ratio */
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);
384 if (ratio < 0) {
385 putc('-', file);
386 ratio = -ratio;
387 } else {
388 putc(' ', file);
390 fprintf(file, "%2ld.%1ld%%", ratio / 10L, ratio % 10L);
394 /* ========================================================================
395 * Semi-safe malloc -- never returns NULL.
397 voidp xmalloc (size)
398 unsigned size;
400 voidp cp = (voidp)malloc (size);
402 if (cp == NULL) error("out of memory");
403 return cp;
406 /* ========================================================================
407 * Table of CRC-32's of all single-byte values (made by makecrc.c)
409 ulg 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