changeset 14000:d8c293f5983b

3682 /usr/bin/head should implement -c -q and -v Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Carlos Cardenas <carlos.cardenas@joyent.com> Reviewed by: Alexander Eremin <alexander.r.eremin@gmail.com> Reviewed by: Peter Tribble <peter.tribble@gmail.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Dan McDonald <danmcd@nexenta.com>
author Robert Mustacchi <rm@joyent.com>
date Wed, 03 Apr 2013 07:45:46 -0700
parents f0c04f0fa2ad
children c55122c1831c
files usr/src/cmd/head/head.c usr/src/man/man1/head.1
diffstat 2 files changed, 88 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/head/head.c	Thu Apr 04 14:26:49 2013 -0400
+++ b/usr/src/cmd/head/head.c	Wed Apr 03 07:45:46 2013 -0700
@@ -36,8 +36,9 @@
  * software developed by the University of California, Berkeley, and its
  * contributors.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
+ */
 
 
 #include <stdio.h>
@@ -49,13 +50,13 @@
 
 #define	DEF_LINE_COUNT	10
 
-static	void	copyout(off_t);
+static	void	copyout(off_t, int);
 static	void	Usage();
 
 
 /*
- * head - give the first few lines of a stream or of each of a set of files
- *
+ * head - give the first few lines of a stream or of each of a set of files.
+ * Optionally shows a specific number of bytes instead.
  */
 int
 main(int argc, char **argv)
@@ -65,7 +66,9 @@
 	int	i;
 	int	opt;
 	off_t	linecnt	= DEF_LINE_COUNT;
+	int	isline = 1;
 	int	error = 0;
+	int	quiet = 0;
 
 	(void) setlocale(LC_ALL, "");
 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
@@ -86,7 +89,7 @@
 				Usage();
 			}
 
-			linecnt = (off_t) strtoll(&argv[i][1], (char **)NULL,
+			linecnt = (off_t)strtoll(&argv[i][1], (char **)NULL,
 			    10);
 			while (i < argc) {
 				argv[i] = argv[i + 1];
@@ -97,23 +100,31 @@
 	}
 
 	/* get options */
-	while ((opt = getopt(argc, argv, "n:")) != EOF) {
+	while ((opt = getopt(argc, argv, "qvn:c:")) != EOF) {
 		switch (opt) {
 		case 'n':
+		case 'c':
 			if ((strcmp(optarg, "--") == 0) || (optind > argc)) {
 				(void) fprintf(stderr, gettext(
-				    "%s: Missing -n argument\n"), argv[0]),
+				    "%s: Missing -%c argument\n"), argv[0],
+				    optopt);
 				Usage();
 			}
-			linecnt = (off_t) strtoll(optarg, (char **)NULL, 10);
+			linecnt = (off_t)strtoll(optarg, (char **)NULL, 10);
 			if (linecnt <= 0) {
 				(void) fprintf(stderr, gettext(
-				    "%s: Invalid \"-n %s\" option\n"),
-				    argv[0], optarg);
+				    "%s: Invalid \"-%c %s\" option\n"),
+				    argv[0], optopt, optarg);
 				Usage();
 			}
+			isline = optopt != 'c';
 			break;
-
+		case 'q':
+			quiet = 1;
+			break;
+		case 'v':
+			quiet = 0;
+			break;
 		default:
 			Usage();
 		}
@@ -135,16 +146,18 @@
 			}
 		}
 
-		if (around)
-			(void) putchar('\n');
+		if (quiet == 0) {
+			if (around)
+				(void) putchar('\n');
 
-		if (fileCount > 1)
-			(void) printf("==> %s <==\n", argv[optind]);
+			if (fileCount > 1)
+				(void) printf("==> %s <==\n", argv[optind]);
+		}
 
 		if (argv[optind] != NULL)
 			optind++;
 
-		copyout(linecnt);
+		copyout(linecnt, isline);
 		(void) fflush(stdout);
 		around++;
 
@@ -154,20 +167,32 @@
 }
 
 static void
-copyout(cnt)
-	register off_t cnt;
+copyout(off_t cnt, int isline)
 {
 	char lbuf[BUFSIZ];
 	size_t len;
 
 	while (cnt > 0 && fgets(lbuf, sizeof (lbuf), stdin) != 0) {
-		(void) printf("%s", lbuf);
-		/* only count as a line if buffer read ends with newline */
-		if ((len = strlen(lbuf)) > 0) {
-			if (lbuf[len - 1] == '\n') {
+		len = strlen(lbuf);
+		if (isline) {
+			(void) printf("%s", lbuf);
+			/*
+			 * only count as a line if buffer read ends with newline
+			 */
+			if (len > 0) {
+				if (lbuf[len - 1] == '\n') {
+					(void) fflush(stdout);
+					cnt--;
+				}
+			}
+		} else {
+			if (len > cnt) {
+				lbuf[cnt] = '\0';
+				len = cnt;
+			}
+			(void) printf("%s", lbuf);
+			cnt -= len;
 			(void) fflush(stdout);
-			cnt--;
-			}
 		}
 	}
 }
@@ -175,6 +200,7 @@
 static void
 Usage()
 {
-	(void) printf(gettext("usage: head [-n #] [-#] [filename...]\n"));
+	(void) printf(gettext("usage: head [-q] [-v] [-n #] [-c #] [-#] "
+	    "[filename...]\n"));
 	exit(1);
 }
--- a/usr/src/man/man1/head.1	Thu Apr 04 14:26:49 2013 -0400
+++ b/usr/src/man/man1/head.1	Wed Apr 03 07:45:46 2013 -0700
@@ -1,4 +1,5 @@
 '\" te
+.\" Portions Copyright (c) 2013, Joyent, Inc. All Rights Reserved
 .\" Copyright (c) 1992, X/Open Company Limited All Rights Reserved Portions
 .\" Copyright 1989 AT&T
 .\" Portions Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved
@@ -10,20 +11,20 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH HEAD 1 "Nov 2, 2007"
+.TH HEAD 1 "Mar	4, 2013"
 .SH NAME
 head \- display first few lines of files
 .SH SYNOPSIS
 .SS "/usr/bin/head"
 .LP
 .nf
-\fB/usr/bin/head\fR [\fB-number\fR | \fB-n\fR \fInumber\fR] [\fIfilename\fR]...
+\fB/usr/bin/head\fR [\fB-q\fR] [\fB-v\fR] [\fB-number\fR ] [ \fB-n\fR \fInumber\fR ] [ \fB-c\fR \fInumber\fR] [\fIfilename\fR]...
 .fi
 
 .SS "ksh93"
 .LP
 .nf
-\fBhead\fR [\fB-qv\fR] [\fB-n\fR \fIlines\fR] [\fB-c\fR \fIchars\fR] [\fB-s\fR \fIskip\fR][\fIfilename\fR]...
+\fBhead\fR [\fB-qv\fR] [\fB-n\fR \fIlines\fR] [\fB-c\fR \fIchars\fR] [\fB-s\fR \fIskip\fR] [\fIfilename\fR]...
 .fi
 
 .SH DESCRIPTION
@@ -33,7 +34,8 @@
 The \fBhead\fR utility copies the first \fInumber\fR of lines of each
 \fIfilename\fR to the standard output. If no \fIfilename\fR is given,
 \fBhead\fR copies lines from the standard input. The default value of
-\fInumber\fR is \fB10\fR lines.
+\fInumber\fR is \fB10\fR lines. If \fB-c\fR is specified, \fBhead\fR
+copies the first \fInumber\fR of bytes of each filename.
 .sp
 .LP
 When more than one file is specified, the start of each file looks like:
@@ -124,6 +126,18 @@
 .sp
 .ne 2
 .na
+\fB\fB-c\fR \fInumber\fR\fR
+.ad
+.RS 13n
+The first \fInumber\fR bytes of each input file is copied to standard output.
+The \fInumber\fR option-argument must be a positive decimal integer. Note,
+output may end in the middle of a character if a file contains multi-byte
+characters.
+.RE
+
+.sp
+.ne 2
+.na
 \fB\fB-\fR\fInumber\fR\fR
 .ad
 .RS 13n
@@ -132,6 +146,24 @@
 .RE
 
 .sp
+.ne 2
+.na
+\fB\FB-q\fR\fR
+.ad
+.RS 13n
+\fBhead\fR will not print a header in between each specified file.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\FB-v\fR\fR
+.ad
+.RS 13n
+\fBhead\fR will always print a header in between each specified file.
+.RE
+
+.sp
 .LP
 If no options are specified, \fBhead\fR acts as if \fB-n\fR \fB10\fR had been
 specified.