xref: /netbsd/usr.bin/head/head.c (revision 0d14b3a6)
1*0d14b3a6Snonaka /*	$NetBSD: head.c,v 1.24 2016/05/12 01:56:44 nonaka Exp $	*/
29d225a17Stls 
361f28255Scgd /*
43ac07874Smrg  * Copyright (c) 1980, 1987, 1992, 1993
53ac07874Smrg  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
323ac07874Smrg #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1992, 1993\
3598e5374cSlukem  The Regents of the University of California.  All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd 
3861f28255Scgd #ifndef lint
393ac07874Smrg #if 0
403ac07874Smrg static char sccsid[] = "@(#)head.c	8.2 (Berkeley) 5/4/95";
413ac07874Smrg #else
42*0d14b3a6Snonaka __RCSID("$NetBSD: head.c,v 1.24 2016/05/12 01:56:44 nonaka Exp $");
433ac07874Smrg #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd 
463ac07874Smrg #include <sys/types.h>
473ac07874Smrg 
483ac07874Smrg #include <ctype.h>
4978a738b3Slukem #include <err.h>
503ac07874Smrg #include <errno.h>
51451c42c3Sjoerg #include <inttypes.h>
52226c774dSkleink #include <limits.h>
53226c774dSkleink #include <locale.h>
5461f28255Scgd #include <stdio.h>
55aab7593aSjtc #include <stdlib.h>
563ac07874Smrg #include <string.h>
572ddbb97fSjtc #include <unistd.h>
58aab7593aSjtc 
5961f28255Scgd /*
6061f28255Scgd  * head - give the first few lines of a stream or of each of a set of files
6161f28255Scgd  *
6261f28255Scgd  * Bill Joy UCB August 24, 1977
6361f28255Scgd  */
6461f28255Scgd 
65451c42c3Sjoerg static void head(FILE *, intmax_t, intmax_t);
6621a8c61aSjoerg static void obsolete(char *[]);
6721a8c61aSjoerg __dead static void usage(void);
683ac07874Smrg 
693ac07874Smrg 
70f7c6bf57Sjtc int
main(int argc,char * argv[])7121a8c61aSjoerg main(int argc, char *argv[])
7261f28255Scgd {
7378a738b3Slukem 	int ch;
743ac07874Smrg 	FILE *fp;
75226c774dSkleink 	int first;
76*0d14b3a6Snonaka 	intmax_t linecnt;
77*0d14b3a6Snonaka 	intmax_t bytecnt;
783ac07874Smrg 	char *ep;
797b1fd4e4Sjoerg 	int eval = 0;
8053e1c6f5Smrg 	int qflag = 0;
8153e1c6f5Smrg 	int vflag = 0;
8261f28255Scgd 
83226c774dSkleink 	(void)setlocale(LC_ALL, "");
843ac07874Smrg 	obsolete(argv);
853ac07874Smrg 	linecnt = 10;
8653e1c6f5Smrg 	bytecnt = 0;
8753e1c6f5Smrg 	while ((ch = getopt(argc, argv, "c:n:qv")) != -1)
88aab7593aSjtc 		switch(ch) {
8953e1c6f5Smrg 		case 'c':
9053e1c6f5Smrg 			errno = 0;
91451c42c3Sjoerg 			bytecnt = strtoimax(optarg, &ep, 10);
92451c42c3Sjoerg 			if ((bytecnt == INTMAX_MAX && errno == ERANGE) ||
93451c42c3Sjoerg 			    *ep || bytecnt <= 0)
94d6c268feSjoerg 				errx(1, "illegal byte count -- %s", optarg);
9553e1c6f5Smrg 			break;
9653e1c6f5Smrg 
97aab7593aSjtc 		case 'n':
98ef83aa34Slukem 			errno = 0;
99451c42c3Sjoerg 			linecnt = strtoimax(optarg, &ep, 10);
100451c42c3Sjoerg 			if ((linecnt == INTMAX_MAX && errno == ERANGE) ||
101451c42c3Sjoerg 			    *ep || linecnt <= 0)
102d6c268feSjoerg 				errx(1, "illegal line count -- %s", optarg);
103aab7593aSjtc 			break;
104aab7593aSjtc 
10553e1c6f5Smrg 		case 'q':
10653e1c6f5Smrg 			qflag = 1;
10753e1c6f5Smrg 			vflag = 0;
10853e1c6f5Smrg 			break;
10953e1c6f5Smrg 
11053e1c6f5Smrg 		case 'v':
11153e1c6f5Smrg 			qflag = 0;
11253e1c6f5Smrg 			vflag = 1;
11353e1c6f5Smrg 			break;
11453e1c6f5Smrg 
1153ac07874Smrg 		case '?':
116aab7593aSjtc 		default:
117aab7593aSjtc 			usage();
118aab7593aSjtc 		}
1193ac07874Smrg 	argc -= optind;
1203ac07874Smrg 	argv += optind;
121aab7593aSjtc 
1223ac07874Smrg 	if (*argv)
1233ac07874Smrg 		for (first = 1; *argv; ++argv) {
1243ac07874Smrg 			if ((fp = fopen(*argv, "r")) == NULL) {
125226c774dSkleink 				warn("%s", *argv);
126226c774dSkleink 				eval = 1;
1273ac07874Smrg 				continue;
12861f28255Scgd 			}
12953e1c6f5Smrg 			if (vflag || (qflag == 0 && argc > 1)) {
1303ac07874Smrg 				(void)printf("%s==> %s <==\n",
1313ac07874Smrg 				    first ? "" : "\n", *argv);
1323ac07874Smrg 				first = 0;
13361f28255Scgd 			}
13453e1c6f5Smrg 			head(fp, linecnt, bytecnt);
1353ac07874Smrg 			(void)fclose(fp);
13661f28255Scgd 		}
1373ac07874Smrg 	else
13853e1c6f5Smrg 		head(stdin, linecnt, bytecnt);
1393ac07874Smrg 	exit(eval);
1403ac07874Smrg }
1413ac07874Smrg 
14221a8c61aSjoerg static void
head(FILE * fp,intmax_t cnt,intmax_t bytecnt)143451c42c3Sjoerg head(FILE *fp, intmax_t cnt, intmax_t bytecnt)
1443ac07874Smrg {
145451c42c3Sjoerg 	char buf[65536];
146451c42c3Sjoerg 	size_t len, rv, rv2;
14778a738b3Slukem 	int ch;
1483ac07874Smrg 
149451c42c3Sjoerg 	if (bytecnt) {
150451c42c3Sjoerg 		while (bytecnt) {
151451c42c3Sjoerg 			len = sizeof(buf);
152451c42c3Sjoerg 			if (bytecnt > (intmax_t)sizeof(buf))
153451c42c3Sjoerg 				len = sizeof(buf);
154451c42c3Sjoerg 			else
155451c42c3Sjoerg 				len = bytecnt;
156451c42c3Sjoerg 			rv = fread(buf, 1, len, fp);
157451c42c3Sjoerg 			if (rv == 0)
158451c42c3Sjoerg 				break; /* Distinguish EOF and error? */
159451c42c3Sjoerg 			rv2 = fwrite(buf, 1, rv, stdout);
160451c42c3Sjoerg 			if (rv2 != rv) {
161451c42c3Sjoerg 				if (feof(stdout))
162451c42c3Sjoerg 					errx(1, "EOF on stdout");
163451c42c3Sjoerg 				else
164451c42c3Sjoerg 					err(1, "failure writing to stdout");
165451c42c3Sjoerg 			}
166451c42c3Sjoerg 			bytecnt -= rv;
167451c42c3Sjoerg 		}
168451c42c3Sjoerg 	} else {
1693ac07874Smrg 		while ((ch = getc(fp)) != EOF) {
1703ac07874Smrg 			if (putchar(ch) == EOF)
171226c774dSkleink 				err(1, "stdout");
172451c42c3Sjoerg 			if (ch == '\n' && --cnt == 0)
17361f28255Scgd 				break;
17461f28255Scgd 		}
17561f28255Scgd 	}
176451c42c3Sjoerg }
177aab7593aSjtc 
17821a8c61aSjoerg static void
obsolete(char * argv[])17921a8c61aSjoerg obsolete(char *argv[])
1803ac07874Smrg {
1813ac07874Smrg 	char *ap;
182aab7593aSjtc 
1833ac07874Smrg 	while ((ap = *++argv)) {
1843ac07874Smrg 		/* Return if "--" or not "-[0-9]*". */
1859794a7e0Schristos 		if (ap[0] != '-' || ap[1] == '-' ||
1869794a7e0Schristos 		    !isdigit((unsigned char)ap[1]))
1873ac07874Smrg 			return;
1883ac07874Smrg 		if ((ap = malloc(strlen(*argv) + 2)) == NULL)
18985cbf55dSdrochner 			err(1, NULL);
1903ac07874Smrg 		ap[0] = '-';
1913ac07874Smrg 		ap[1] = 'n';
1923ac07874Smrg 		(void)strcpy(ap + 2, *argv + 1);
1933ac07874Smrg 		*argv = ap;
1943ac07874Smrg 	}
1953ac07874Smrg }
1963ac07874Smrg 
19721a8c61aSjoerg static void
usage(void)19821a8c61aSjoerg usage(void)
199aab7593aSjtc {
200a8ec668dScgd 
201b635f565Sjmmv 	(void)fprintf(stderr, "usage: %s [-n lines] [file ...]\n",
202a8ec668dScgd 	    getprogname());
203aab7593aSjtc 	exit(1);
204aab7593aSjtc }
205