Jeremie Courreges-Anglas wrote:
> Today someone bumped into a port that contained head -c calls. While
> upstream could be prodded to care a bit more about portability, support
> for head -c is widespread (GNU coreutils, busybox, FreeBSD, NetBSD) so
> I don't see any value in being different. Plus, tail(1) already has
> support for -c.
>
> Comments/ok?
Makes sense and works for me. I'll leave a few comments inline. Also:
> PS: the next diff will remove documentation for the obsolete "-count"
> syntax.
In what sense is it obsolete? I've always used this and I think it's
pretty standard these days. Now that I look, it seems that GNU head(1)
has it but FreeBSD's and NetBSD's don't. I'd be sad to see it go.
> Index: head.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/head/head.c,v
> retrieving revision 1.20
> diff -u -p -r1.20 head.c
> --- head.c 9 Oct 2015 01:37:07 -0000 1.20
> +++ head.c 9 Mar 2016 20:02:08 -0000
> @@ -51,9 +51,9 @@ main(int argc, char *argv[])
> FILE *fp;
> long cnt;
> int ch, firsttime;
> - long linecnt = 10;
> + long count = 10;
It seems like it'd be better to make this a long long for the sake of
robustness. It's conceivable that someone could try to truncate a file
to a few gigabytes.
> char *p = NULL;
> - int status = 0;
> + int dobytes = 0, status = 0;
I'd definitely prefer stdbool here, but that's contentious.
>
> if (pledge("stdio rpath", NULL) == -1)
> err(1, "pledge");
> @@ -66,13 +66,18 @@ main(int argc, char *argv[])
> argv++;
> }
>
> - while ((ch = getopt(argc, argv, "n:")) != -1) {
> + while ((ch = getopt(argc, argv, "c:n:")) != -1) {
> switch (ch) {
> + case 'c':
> + dobytes = 1;
> + p = optarg;
> + break;
> case 'n':
> + dobytes = 0;
It's already initialized to 0, which is necessary for the head -count
style syntax.
> p = optarg;
> break;
> default:
> - usage();
> + usage();
Good catch.
> }
> }
> argc -= optind, argv += optind;
> @@ -80,9 +85,10 @@ main(int argc, char *argv[])
> if (p) {
> const char *errstr;
>
> - linecnt = strtonum(p, 1, LONG_MAX, &errstr);
> + count = strtonum(p, 1, LONG_MAX, &errstr);
If using long long, this would have to change too.
> if (errstr)
> - errx(1, "line count %s: %s", errstr, p);
> + errx(1, "%s count %s: %s", dobytes ? "bytes" : "lines",
> + errstr, p);
> }
>
> for (firsttime = 1; ; firsttime = 0) {
> @@ -105,10 +111,16 @@ main(int argc, char *argv[])
> }
> ++argv;
> }
> - for (cnt = linecnt; cnt && !feof(fp); --cnt)
> - while ((ch = getc(fp)) != EOF)
> - if (putchar(ch) == '\n')
> - break;
> + if (dobytes) {
> + for (cnt = count; cnt && !feof(fp); --cnt)
> + if ((ch = getc(fp)) != EOF)
> + putchar(ch);
> + } else {
> + for (cnt = count; cnt && !feof(fp); --cnt)
> + while ((ch = getc(fp)) != EOF)
> + if (putchar(ch) == '\n')
> + break;
> + }
Total nitpick, but I think switching the for loop condition to "cnt > 0
&& !feof(fp)" would be nice.
> fclose(fp);
> }
> /*NOTREACHED*/
Might as well delete /*NOTREACHED*/