xref: /dragonfly/usr.bin/head/head.c (revision 029e6489)
1 /*
2  * Copyright (c) 1980, 1987, 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)head.c	8.2 (Berkeley) 5/4/95
30  * $FreeBSD: src/usr.bin/head/head.c,v 1.10.2.1 2002/02/16 12:29:04 dwmalone Exp $
31  */
32 
33 #include <ctype.h>
34 #include <err.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 /*
42  * head - give the first few lines of a stream or of each of a set of files
43  *
44  * Bill Joy UCB August 24, 1977
45  */
46 
47 static void	head(FILE *, size_t);
48 static void	head_bytes(FILE *, size_t);
49 static void	obsolete(char *[]);
50 static void	usage(void) __dead2;
51 
52 int
53 main(int argc, char **argv)
54 {
55 	int ch;
56 	FILE *fp;
57 	bool first;
58 	bool qflag = false, vflag = false;
59 	int linecnt = -1, bytecnt = -1, eval = 0;
60 	char *ep;
61 
62 	obsolete(argv);
63 	while ((ch = getopt(argc, argv, "c:n:qv")) != -1) {
64 		switch(ch) {
65 		case 'c':
66 			bytecnt = strtol(optarg, &ep, 10);
67 			if (*ep != 0 || bytecnt <= 0)
68 				errx(1, "illegal byte count -- %s", optarg);
69 			break;
70 		case 'n':
71 			linecnt = strtol(optarg, &ep, 10);
72 			if (*ep != 0 || linecnt <= 0)
73 				errx(1, "illegal line count -- %s", optarg);
74 			break;
75 		case 'q':
76 			qflag = true;
77 			vflag = false;
78 			break;
79 		case 'v':
80 			vflag = true;
81 			qflag = false;
82 			break;
83 		default:
84 			usage();
85 		}
86 	}
87 	argc -= optind;
88 	argv += optind;
89 
90 	if (linecnt != -1 && bytecnt != -1)
91 		errx(1, "can't combine line and byte counts");
92 	if (linecnt == -1 )
93 		linecnt = 10;
94 	if (*argv) {
95 		first = true;
96 		for (; *argv; ++argv) {
97 			if ((fp = fopen(*argv, "r")) == NULL) {
98 				warn("%s", *argv);
99 				eval = 1;
100 				continue;
101 			}
102 			if (vflag || (!qflag && argc > 1)) {
103 				printf("%s==> %s <==\n",
104 				    first ? "" : "\n", *argv);
105 				first = false;
106 			}
107 			if (bytecnt == -1)
108 				head(fp, linecnt);
109 			else
110 				head_bytes(fp, bytecnt);
111 			fclose(fp);
112 		}
113 	} else if (bytecnt == -1)
114 		head(stdin, linecnt);
115 	else
116 		head_bytes(stdin, bytecnt);
117 
118 	exit(eval);
119 }
120 
121 static void
122 head(FILE *fp, size_t cnt)
123 {
124 	char *cp;
125 	size_t error, readlen;
126 
127 	while (cnt && (cp = fgetln(fp, &readlen)) != NULL) {
128 		error = fwrite(cp, sizeof(char), readlen, stdout);
129 		if (error != readlen)
130 			err(1, "stdout");
131 		cnt--;
132 	}
133 }
134 
135 static void
136 head_bytes(FILE *fp, size_t cnt)
137 {
138 	char buf[4096];
139 	size_t readlen;
140 
141 	while (cnt) {
142 		if (cnt < sizeof(buf))
143 			readlen = cnt;
144 		else
145 			readlen = sizeof(buf);
146 		readlen = fread(buf, sizeof(char), readlen, fp);
147 		if (readlen == 0)
148 			break;
149 		if (fwrite(buf, sizeof(char), readlen, stdout) != readlen)
150 			err(1, "stdout");
151 		cnt -= readlen;
152 	}
153 }
154 
155 static void
156 obsolete(char **argv)
157 {
158 	char *ap;
159 
160 	while ((ap = *++argv)) {
161 		/* Return if "--" or not "-[0-9]*". */
162 		if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1]))
163 			return;
164 		if ((ap = malloc(strlen(*argv) + 2)) == NULL)
165 			err(1, "malloc failed");
166 		ap[0] = '-';
167 		ap[1] = 'n';
168 		strcpy(ap + 2, *argv + 1);
169 		*argv = ap;
170 	}
171 }
172 
173 static void __dead2
174 usage(void)
175 {
176 	fprintf(stderr,
177 		"usage: head [-q | -v] [-n lines | -c bytes] [file ...]\n");
178 	exit(1);
179 }
180