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);
 }

Reply via email to