Home | History | Annotate | Line # | Download | only in compress
compress.c revision 1.24.6.1
      1  1.24.6.1       jym /*	$NetBSD: compress.c,v 1.24.6.1 2009/05/13 19:19:47 jym Exp $	*/
      2       1.9     glass 
      3       1.6       cgd /*-
      4       1.6       cgd  * Copyright (c) 1992, 1993
      5       1.6       cgd  *	The Regents of the University of California.  All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8       1.1       cgd  * modification, are permitted provided that the following conditions
      9       1.1       cgd  * are met:
     10       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15      1.20       agc  * 3. Neither the name of the University nor the names of its contributors
     16       1.1       cgd  *    may be used to endorse or promote products derived from this software
     17       1.1       cgd  *    without specific prior written permission.
     18       1.1       cgd  *
     19       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29       1.1       cgd  * SUCH DAMAGE.
     30       1.1       cgd  */
     31       1.1       cgd 
     32      1.13     lukem #include <sys/cdefs.h>
     33       1.1       cgd #ifndef lint
     34      1.24     lukem __COPYRIGHT("@(#) Copyright (c) 1992, 1993\
     35      1.24     lukem  The Regents of the University of California.  All rights reserved.");
     36       1.1       cgd #endif /* not lint */
     37       1.1       cgd 
     38       1.1       cgd #ifndef lint
     39       1.9     glass #if 0
     40       1.9     glass static char sccsid[] = "@(#)compress.c	8.2 (Berkeley) 1/7/94";
     41       1.9     glass #else
     42  1.24.6.1       jym __RCSID("$NetBSD: compress.c,v 1.24.6.1 2009/05/13 19:19:47 jym Exp $");
     43       1.9     glass #endif
     44       1.1       cgd #endif /* not lint */
     45       1.1       cgd 
     46       1.1       cgd #include <sys/param.h>
     47       1.6       cgd #include <sys/time.h>
     48       1.1       cgd #include <sys/stat.h>
     49       1.6       cgd 
     50       1.6       cgd #include <err.h>
     51       1.1       cgd #include <errno.h>
     52      1.19       wiz #include <stdarg.h>
     53       1.1       cgd #include <stdio.h>
     54       1.1       cgd #include <stdlib.h>
     55       1.1       cgd #include <string.h>
     56       1.6       cgd #include <unistd.h>
     57       1.1       cgd 
     58  1.24.6.1       jym void	compress(const char *, const char *, int);
     59      1.19       wiz void	cwarn(const char *, ...) __attribute__((__format__(__printf__,1,2)));
     60      1.19       wiz void	cwarnx(const char *, ...) __attribute__((__format__(__printf__,1,2)));
     61  1.24.6.1       jym void	decompress(const char *, const char *, int);
     62  1.24.6.1       jym int	permission(const char *);
     63  1.24.6.1       jym void	setfile(const char *, struct stat *);
     64      1.19       wiz void	usage(int);
     65       1.8       cgd 
     66      1.19       wiz int	main(int, char *[]);
     67      1.19       wiz extern FILE *zopen(const char *fname, const char *mode, int bits);
     68       1.1       cgd 
     69       1.6       cgd int eval, force, verbose;
     70      1.10       mrg int isstdout, isstdin;
     71       1.1       cgd 
     72       1.6       cgd int
     73      1.19       wiz main(int argc, char **argv)
     74       1.1       cgd {
     75      1.17  wsanchez         enum {COMPRESS, DECOMPRESS} style = COMPRESS;
     76       1.6       cgd 	size_t len;
     77       1.6       cgd 	int bits, cat, ch;
     78       1.6       cgd 	char *p, newname[MAXPATHLEN];
     79       1.1       cgd 
     80      1.13     lukem 	if ((p = strrchr(argv[0], '/')) == NULL)
     81       1.6       cgd 		p = argv[0];
     82       1.6       cgd 	else
     83       1.6       cgd 		++p;
     84       1.6       cgd 	if (!strcmp(p, "uncompress"))
     85       1.6       cgd 		style = DECOMPRESS;
     86      1.17  wsanchez         else if (!strcmp(p, "compress"))
     87      1.17  wsanchez                 style = COMPRESS;
     88      1.17  wsanchez         else if (!strcmp(p, "zcat")) {
     89      1.17  wsanchez                 style = DECOMPRESS;
     90      1.17  wsanchez                 cat = 1;
     91      1.17  wsanchez         }
     92       1.1       cgd 	else
     93       1.6       cgd 		errx(1, "unknown program name");
     94       1.1       cgd 
     95       1.6       cgd 	bits = cat = 0;
     96      1.14     lukem 	while ((ch = getopt(argc, argv, "b:cdfv")) != -1)
     97       1.1       cgd 		switch(ch) {
     98       1.1       cgd 		case 'b':
     99       1.6       cgd 			bits = strtol(optarg, &p, 10);
    100       1.6       cgd 			if (*p)
    101       1.6       cgd 				errx(1, "illegal bit count -- %s", optarg);
    102       1.1       cgd 			break;
    103       1.1       cgd 		case 'c':
    104       1.6       cgd 			cat = 1;
    105       1.1       cgd 			break;
    106       1.6       cgd 		case 'd':		/* Backward compatible. */
    107       1.6       cgd 			style = DECOMPRESS;
    108       1.1       cgd 			break;
    109       1.1       cgd 		case 'f':
    110       1.1       cgd 			force = 1;
    111       1.1       cgd 			break;
    112       1.6       cgd 		case 'v':
    113       1.1       cgd 			verbose = 1;
    114       1.1       cgd 			break;
    115       1.1       cgd 		case '?':
    116       1.1       cgd 		default:
    117       1.6       cgd 			usage(style == COMPRESS);
    118       1.1       cgd 		}
    119       1.1       cgd 	argc -= optind;
    120       1.1       cgd 	argv += optind;
    121       1.1       cgd 
    122       1.6       cgd 	if (argc == 0) {
    123       1.6       cgd 		switch(style) {
    124       1.6       cgd 		case COMPRESS:
    125      1.10       mrg 			isstdout = 1;
    126      1.10       mrg 			isstdin = 1;
    127       1.6       cgd 			(void)compress("/dev/stdin", "/dev/stdout", bits);
    128       1.6       cgd 			break;
    129       1.6       cgd 		case DECOMPRESS:
    130      1.10       mrg 			isstdout = 1;
    131      1.10       mrg 			isstdin = 1;
    132       1.6       cgd 			(void)decompress("/dev/stdin", "/dev/stdout", bits);
    133       1.6       cgd 			break;
    134       1.1       cgd 		}
    135       1.6       cgd 		exit (eval);
    136       1.6       cgd 	}
    137       1.6       cgd 
    138       1.6       cgd 	if (cat == 1 && argc > 1)
    139       1.6       cgd 		errx(1, "the -c option permits only a single file argument");
    140       1.6       cgd 
    141      1.11    abrown 	for (; *argv; ++argv) {
    142      1.10       mrg 		isstdout = 0;
    143       1.6       cgd 		switch(style) {
    144       1.6       cgd 		case COMPRESS:
    145       1.6       cgd 			if (cat) {
    146      1.10       mrg 				isstdout = 1;
    147       1.6       cgd 				compress(*argv, "/dev/stdout", bits);
    148       1.6       cgd 				break;
    149       1.6       cgd 			}
    150      1.13     lukem 			if ((p = strrchr(*argv, '.')) != NULL &&
    151       1.6       cgd 			    !strcmp(p, ".Z")) {
    152       1.6       cgd 				cwarnx("%s: name already has trailing .Z",
    153       1.6       cgd 				    *argv);
    154       1.6       cgd 				break;
    155       1.6       cgd 			}
    156       1.6       cgd 			len = strlen(*argv);
    157       1.6       cgd 			if (len > sizeof(newname) - 3) {
    158       1.6       cgd 				cwarnx("%s: name too long", *argv);
    159       1.6       cgd 				break;
    160       1.6       cgd 			}
    161       1.6       cgd 			memmove(newname, *argv, len);
    162       1.6       cgd 			newname[len] = '.';
    163       1.6       cgd 			newname[len + 1] = 'Z';
    164       1.6       cgd 			newname[len + 2] = '\0';
    165       1.6       cgd 			compress(*argv, newname, bits);
    166       1.6       cgd 			break;
    167       1.6       cgd 		case DECOMPRESS:
    168       1.6       cgd 			len = strlen(*argv);
    169      1.13     lukem 			if ((p = strrchr(*argv, '.')) == NULL ||
    170       1.6       cgd 			    strcmp(p, ".Z")) {
    171       1.6       cgd 				if (len > sizeof(newname) - 3) {
    172       1.6       cgd 					cwarnx("%s: name too long", *argv);
    173       1.6       cgd 					break;
    174       1.6       cgd 				}
    175       1.6       cgd 				memmove(newname, *argv, len);
    176       1.6       cgd 				newname[len] = '.';
    177       1.6       cgd 				newname[len + 1] = 'Z';
    178       1.6       cgd 				newname[len + 2] = '\0';
    179       1.6       cgd 				decompress(newname,
    180       1.6       cgd 				    cat ? "/dev/stdout" : *argv, bits);
    181      1.10       mrg 				if (cat)
    182      1.10       mrg 					isstdout = 1;
    183       1.6       cgd 			} else {
    184       1.6       cgd 				if (len - 2 > sizeof(newname) - 1) {
    185       1.6       cgd 					cwarnx("%s: name too long", *argv);
    186       1.6       cgd 					break;
    187       1.6       cgd 				}
    188       1.6       cgd 				memmove(newname, *argv, len - 2);
    189       1.6       cgd 				newname[len - 2] = '\0';
    190       1.6       cgd 				decompress(*argv,
    191       1.6       cgd 				    cat ? "/dev/stdout" : newname, bits);
    192      1.10       mrg 				if (cat)
    193      1.10       mrg 					isstdout = 1;
    194       1.1       cgd 			}
    195       1.6       cgd 			break;
    196       1.1       cgd 		}
    197      1.11    abrown 	}
    198       1.6       cgd 	exit (eval);
    199       1.6       cgd }
    200       1.6       cgd 
    201       1.6       cgd void
    202  1.24.6.1       jym compress(const char *in, const char *out, int bits)
    203       1.6       cgd {
    204  1.24.6.1       jym 	size_t nr;
    205       1.6       cgd 	struct stat isb, sb;
    206      1.23  christos 	const char *error = NULL;
    207       1.6       cgd 	FILE *ifp, *ofp;
    208       1.6       cgd 	int exists, isreg, oreg;
    209      1.12     mikel 	u_char buf[BUFSIZ];
    210       1.6       cgd 
    211      1.10       mrg 	if (!isstdout) {
    212      1.10       mrg 		exists = !stat(out, &sb);
    213      1.10       mrg 		if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
    214      1.10       mrg 			return;
    215      1.10       mrg 		oreg = !exists || S_ISREG(sb.st_mode);
    216      1.10       mrg 	} else
    217      1.12     mikel 		oreg = 0;
    218       1.6       cgd 
    219       1.6       cgd 	ifp = ofp = NULL;
    220       1.6       cgd 	if ((ifp = fopen(in, "r")) == NULL) {
    221       1.6       cgd 		cwarn("%s", in);
    222       1.6       cgd 		return;
    223       1.6       cgd 	}
    224      1.10       mrg 
    225      1.10       mrg 	if (!isstdin) {
    226      1.10       mrg 		if (stat(in, &isb)) {		/* DON'T FSTAT! */
    227      1.10       mrg 			cwarn("%s", in);
    228      1.10       mrg 			goto err;
    229      1.10       mrg 		}
    230      1.10       mrg 		if (!S_ISREG(isb.st_mode))
    231      1.10       mrg 			isreg = 0;
    232      1.10       mrg 		else
    233      1.10       mrg 			isreg = 1;
    234      1.10       mrg 	} else
    235       1.6       cgd 		isreg = 0;
    236       1.6       cgd 
    237       1.6       cgd 	if ((ofp = zopen(out, "w", bits)) == NULL) {
    238       1.6       cgd 		cwarn("%s", out);
    239       1.6       cgd 		goto err;
    240       1.6       cgd 	}
    241      1.22       dsl 	oreg <<= 1;
    242       1.6       cgd 	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
    243       1.6       cgd 		if (fwrite(buf, 1, nr, ofp) != nr) {
    244       1.6       cgd 			cwarn("%s", out);
    245       1.6       cgd 			goto err;
    246       1.6       cgd 		}
    247       1.6       cgd 
    248      1.23  christos 	if (ferror(ifp))
    249      1.23  christos 		error = in;
    250      1.23  christos 	if (fclose(ifp))
    251      1.23  christos 		if (error == NULL)
    252      1.23  christos 			error = in;
    253      1.23  christos 	if (fclose(ofp))
    254      1.23  christos 		if (error == NULL)
    255      1.23  christos 			error = out;
    256       1.6       cgd 	ifp = NULL;
    257      1.23  christos 	ofp = NULL;
    258      1.23  christos 	if (error) {
    259      1.23  christos 		cwarn("%s", error);
    260       1.6       cgd 		goto err;
    261       1.6       cgd 	}
    262       1.6       cgd 
    263      1.12     mikel 	if (isreg && oreg) {
    264       1.6       cgd 		if (stat(out, &sb)) {
    265       1.6       cgd 			cwarn("%s", out);
    266       1.6       cgd 			goto err;
    267       1.6       cgd 		}
    268       1.6       cgd 
    269       1.6       cgd 		if (!force && sb.st_size >= isb.st_size) {
    270       1.6       cgd 			if (verbose)
    271       1.6       cgd 		(void)printf("%s: file would grow; left unmodified\n", in);
    272       1.6       cgd 			goto err;
    273       1.6       cgd 		}
    274       1.6       cgd 
    275       1.6       cgd 		setfile(out, &isb);
    276       1.6       cgd 
    277       1.6       cgd 		if (unlink(in))
    278       1.6       cgd 			cwarn("%s", in);
    279       1.6       cgd 
    280       1.6       cgd 		if (verbose) {
    281       1.6       cgd 			(void)printf("%s: ", out);
    282       1.6       cgd 			if (isb.st_size > sb.st_size)
    283       1.6       cgd 				(void)printf("%.0f%% compression\n",
    284      1.15   mycroft 				    ((double)sb.st_size / isb.st_size) * 100.0);
    285       1.6       cgd 			else
    286       1.6       cgd 				(void)printf("%.0f%% expansion\n",
    287      1.15   mycroft 				    ((double)isb.st_size / sb.st_size) * 100.0);
    288       1.1       cgd 		}
    289       1.1       cgd 	}
    290       1.6       cgd 	return;
    291       1.6       cgd 
    292      1.22       dsl err:	if (ofp)
    293       1.6       cgd 		(void)fclose(ofp);
    294      1.22       dsl 	if (oreg == 2)
    295      1.22       dsl 		(void)unlink(out);
    296       1.6       cgd 	if (ifp)
    297       1.6       cgd 		(void)fclose(ifp);
    298       1.1       cgd }
    299       1.1       cgd 
    300       1.6       cgd void
    301  1.24.6.1       jym decompress(const char *in, const char *out, int bits)
    302       1.6       cgd {
    303  1.24.6.1       jym 	size_t nr;
    304       1.6       cgd 	struct stat sb;
    305       1.6       cgd 	FILE *ifp, *ofp;
    306       1.6       cgd 	int exists, isreg, oreg;
    307      1.12     mikel 	u_char buf[BUFSIZ];
    308       1.1       cgd 
    309      1.10       mrg 	if (!isstdout) {
    310      1.10       mrg 		exists = !stat(out, &sb);
    311      1.10       mrg 		if (!force && exists && S_ISREG(sb.st_mode) && !permission(out))
    312      1.10       mrg 			return;
    313      1.10       mrg 		oreg = !exists || S_ISREG(sb.st_mode);
    314      1.10       mrg 	} else
    315      1.12     mikel 		oreg = 0;
    316       1.1       cgd 
    317       1.6       cgd 	ifp = ofp = NULL;
    318       1.6       cgd 	if ((ofp = fopen(out, "w")) == NULL) {
    319       1.6       cgd 		cwarn("%s", out);
    320       1.6       cgd 		return;
    321       1.6       cgd 	}
    322       1.1       cgd 
    323       1.6       cgd 	if ((ifp = zopen(in, "r", bits)) == NULL) {
    324       1.6       cgd 		cwarn("%s", in);
    325       1.6       cgd 		goto err;
    326       1.1       cgd 	}
    327      1.10       mrg 	if (!isstdin) {
    328      1.10       mrg 		if (stat(in, &sb)) {
    329      1.10       mrg 			cwarn("%s", in);
    330      1.10       mrg 			goto err;
    331      1.10       mrg 		}
    332      1.10       mrg 		if (!S_ISREG(sb.st_mode))
    333      1.10       mrg 			isreg = 0;
    334      1.10       mrg 		else
    335      1.10       mrg 			isreg = 1;
    336      1.10       mrg 	} else
    337       1.6       cgd 		isreg = 0;
    338       1.1       cgd 
    339      1.22       dsl 	oreg <<= 1;
    340       1.6       cgd 	while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
    341       1.6       cgd 		if (fwrite(buf, 1, nr, ofp) != nr) {
    342       1.6       cgd 			cwarn("%s", out);
    343       1.6       cgd 			goto err;
    344       1.6       cgd 		}
    345       1.1       cgd 
    346      1.22       dsl 	if (ferror(ifp)) {
    347      1.22       dsl 		cwarn("%s", in);
    348      1.22       dsl 		goto err;
    349      1.22       dsl 	}
    350      1.22       dsl 	if (fclose(ifp)) {
    351      1.22       dsl 		ifp = NULL;
    352       1.6       cgd 		cwarn("%s", in);
    353       1.6       cgd 		goto err;
    354       1.1       cgd 	}
    355       1.6       cgd 	ifp = NULL;
    356       1.1       cgd 
    357       1.6       cgd 	if (fclose(ofp)) {
    358      1.22       dsl 		ofp = NULL;
    359       1.6       cgd 		cwarn("%s", out);
    360       1.6       cgd 		goto err;
    361       1.1       cgd 	}
    362       1.1       cgd 
    363      1.12     mikel 	if (isreg && oreg) {
    364       1.6       cgd 		setfile(out, &sb);
    365       1.1       cgd 
    366       1.6       cgd 		if (unlink(in))
    367       1.6       cgd 			cwarn("%s", in);
    368       1.1       cgd 	}
    369       1.6       cgd 	return;
    370       1.1       cgd 
    371      1.22       dsl err:	if (ofp)
    372       1.6       cgd 		(void)fclose(ofp);
    373      1.22       dsl 	if (oreg == 2)
    374      1.22       dsl 		(void)unlink(out);
    375       1.6       cgd 	if (ifp)
    376       1.6       cgd 		(void)fclose(ifp);
    377       1.6       cgd }
    378       1.1       cgd 
    379       1.6       cgd void
    380  1.24.6.1       jym setfile(const char *name, struct stat *fs)
    381       1.6       cgd {
    382       1.6       cgd 	static struct timeval tv[2];
    383       1.1       cgd 
    384       1.6       cgd 	fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
    385       1.1       cgd 
    386       1.6       cgd 	TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
    387       1.6       cgd 	TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
    388       1.6       cgd 	if (utimes(name, tv))
    389       1.6       cgd 		cwarn("utimes: %s", name);
    390       1.1       cgd 
    391       1.1       cgd 	/*
    392       1.6       cgd 	 * Changing the ownership probably won't succeed, unless we're root
    393       1.6       cgd 	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
    394       1.6       cgd 	 * the mode; current BSD behavior is to remove all setuid bits on
    395       1.6       cgd 	 * chown.  If chown fails, lose setuid/setgid bits.
    396       1.1       cgd 	 */
    397       1.6       cgd 	if (chown(name, fs->st_uid, fs->st_gid)) {
    398       1.6       cgd 		if (errno != EPERM)
    399       1.6       cgd 			cwarn("chown: %s", name);
    400       1.6       cgd 		fs->st_mode &= ~(S_ISUID|S_ISGID);
    401       1.1       cgd 	}
    402       1.6       cgd 	if (chmod(name, fs->st_mode))
    403       1.6       cgd 		cwarn("chown: %s", name);
    404       1.1       cgd 
    405      1.16    kleink 	/*
    406      1.16    kleink 	 * Restore the file's flags.  However, do this only if the original
    407      1.16    kleink 	 * file had any flags set; this avoids a warning on file-systems that
    408      1.16    kleink 	 * do not support flags.
    409      1.16    kleink 	 */
    410      1.16    kleink 	if (fs->st_flags != 0 && chflags(name, fs->st_flags))
    411       1.6       cgd 		cwarn("chflags: %s", name);
    412       1.1       cgd }
    413       1.1       cgd 
    414       1.6       cgd int
    415  1.24.6.1       jym permission(const char *fname)
    416       1.1       cgd {
    417       1.6       cgd 	int ch, first;
    418       1.1       cgd 
    419       1.6       cgd 	if (!isatty(fileno(stderr)))
    420       1.6       cgd 		return (0);
    421       1.6       cgd 	(void)fprintf(stderr, "overwrite %s? ", fname);
    422       1.6       cgd 	first = ch = getchar();
    423       1.6       cgd 	while (ch != '\n' && ch != EOF)
    424       1.6       cgd 		ch = getchar();
    425       1.6       cgd 	return (first == 'y');
    426       1.1       cgd }
    427       1.1       cgd 
    428       1.6       cgd void
    429      1.19       wiz usage(int iscompress)
    430       1.1       cgd {
    431       1.6       cgd 	if (iscompress)
    432       1.6       cgd 		(void)fprintf(stderr,
    433      1.21       wiz 		    "usage: compress [-cdfv] [-b bits] [file ...]\n");
    434       1.6       cgd 	else
    435       1.6       cgd 		(void)fprintf(stderr,
    436      1.21       wiz 		    "usage: uncompress [-cdfv] [-b bits] [file ...]\n");
    437       1.1       cgd 	exit(1);
    438       1.1       cgd }
    439       1.1       cgd 
    440       1.1       cgd void
    441       1.6       cgd cwarnx(const char *fmt, ...)
    442       1.1       cgd {
    443       1.6       cgd 	va_list ap;
    444      1.19       wiz 
    445       1.6       cgd 	va_start(ap, fmt);
    446       1.6       cgd 	vwarnx(fmt, ap);
    447       1.6       cgd 	va_end(ap);
    448       1.6       cgd 	eval = 1;
    449       1.1       cgd }
    450       1.1       cgd 
    451       1.1       cgd void
    452       1.6       cgd cwarn(const char *fmt, ...)
    453       1.1       cgd {
    454       1.6       cgd 	va_list ap;
    455      1.19       wiz 
    456       1.6       cgd 	va_start(ap, fmt);
    457       1.6       cgd 	vwarn(fmt, ap);
    458       1.6       cgd 	va_end(ap);
    459       1.6       cgd 	eval = 1;
    460       1.1       cgd }
    461