Hello, this is my first patch to OpenBSD. I look forward to feedback on code as
well as process, communication, etc. Thank you in advance.
This patch adds a -c <bytes> argument to head(1). The behavior is intended to
be the same as head on other systems, such as FreeBSD, NetBSD, macOS,
and Linux.
diff --git usr.bin/head/head.1 usr.bin/head/head.1
index 8f97660ef25..d3cb84dc462 100644
--- usr.bin/head/head.1
+++ usr.bin/head/head.1
@@ -34,17 +34,19 @@
.Os
.Sh NAME
.Nm head
-.Nd display first few lines of files
+.Nd display first few lines or bytes of files
.Sh SYNOPSIS
.Nm head
-.Op Fl Ar count | Fl n Ar count
+.Op Fl Ar count | Fl n Ar count | Fl c Ar bytes
.Op Ar
.Sh DESCRIPTION
The
.Nm
utility copies the first
.Ar count
-lines of each specified
+lines or
+.Ar bytes
+of each specified
.Ar file
to the standard output.
If no files are named,
@@ -63,6 +65,14 @@ lines of each input file to the standard output.
.Ar count
must be a positive decimal integer.
.El
+.Bl -tag -width Ds
+.It Fl c Ar bytes
+Copy the first
+.Ar bytes
+of each input file to the standard output.
+.Ar bytes
+must be a positive decimal integer.
+.El
.Pp
If more than one file is specified,
.Nm
@@ -70,6 +80,12 @@ precedes the output of each file with the following, in order
to distinguish files:
.Pp
.Dl ==> Ar file No <==
+.Pp
+It is an error to specify both
+.Ar count
+and
+.Ar bytes
+arguments.
.Sh EXIT STATUS
.Ex -std head
.Sh EXAMPLES
@@ -85,6 +101,13 @@ in the following way to, for example, display only
line 500 from the file
.Ar foo :
.Pp
.Dl $ head -n 500 foo | tail -1
+.Pp
+.Nm
+can be used in conjunction
+.Xr urandom 4
+to create a random string of bytes:
+.Pp
+.Dl $ head -c 32 /dev/urandom | base64
.Sh SEE ALSO
.Xr cat 1 ,
.Xr cut 1 ,
diff --git usr.bin/head/head.c usr.bin/head/head.c
index 73670621524..1fc860929c9 100644
--- usr.bin/head/head.c
+++ usr.bin/head/head.c
@@ -37,7 +37,7 @@
#include <errno.h>
#include <unistd.h>
-int head_file(const char *, long, int);
+int head_file(const char *, long, long, int);
static void usage(void);
/*
@@ -51,7 +51,8 @@ main(int argc, char *argv[])
{
const char *errstr;
int ch;
- long linecnt = 10;
+ long linecnt = -1;
+ long bytecnt = -1;
int status = 0;
if (pledge("stdio rpath", NULL) == -1)
@@ -67,12 +68,17 @@ main(int argc, char *argv[])
argv++;
}
- while ((ch = getopt(argc, argv, "n:")) != -1) {
+ while ((ch = getopt(argc, argv, "n:c:")) != -1) {
switch (ch) {
case 'n':
linecnt = strtonum(optarg, 1, LONG_MAX, &errstr);
if (errstr != NULL)
- errx(1, "count is %s: %s", errstr, optarg);
+ errx(1, "line count is %s: %s", errstr, optarg);
+ break;
+ case 'c':
+ bytecnt = strtonum(optarg, 1, LONG_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "byte count is %s: %s", errstr, optarg);
break;
default:
usage();
@@ -80,26 +86,32 @@ main(int argc, char *argv[])
}
argc -= optind, argv += optind;
+ if (linecnt != -1 && bytecnt != -1)
+ errx(1, "cannot specify both line and byte counts");
+ if (linecnt == -1 && bytecnt == -1)
+ linecnt = 10;
+
if (argc == 0) {
if (pledge("stdio", NULL) == -1)
err(1, "pledge");
- status = head_file(NULL, linecnt, 0);
+ status = head_file(NULL, linecnt, bytecnt, 0);
} else {
for (; *argv != NULL; argv++)
- status |= head_file(*argv, linecnt, argc > 1);
+ status |= head_file(*argv, linecnt, bytecnt, argc > 1);
}
return status;
}
int
-head_file(const char *path, long count, int need_header)
+head_file(const char *path, long linecnt, long bytecnt, int need_header)
{
const char *name;
FILE *fp;
int ch, status = 0;
static int first = 1;
+ long count = (linecnt != -1) ? linecnt : bytecnt;
if (path != NULL) {
name = path;
@@ -122,7 +134,7 @@ head_file(const char *path, long count, int need_header)
while ((ch = getc(fp)) != EOF) {
if (putchar(ch) == EOF)
err(1, "stdout");
- if (ch == '\n' && --count == 0)
+ if ((bytecnt != -1 || ch == '\n') && --count == 0)
break;
}
if (ferror(fp)) {
@@ -139,6 +151,6 @@ head_file(const char *path, long count, int need_header)
static void
usage(void)
{
- fputs("usage: head [-count | -n count] [file ...]\n", stderr);
+ fputs("usage: head [-count | -n count | -c bytes] [file ...]\n", stderr);
exit(1);
}