On Tue, Nov 02, 2021 at 08:12:00AM -0600, Todd C. Miller wrote:
> On Mon, 01 Nov 2021 21:04:54 -0500, Scott Cheloha wrote:
>
> > Yes it would be simpler. However I didn't want to start changing the
> > input -- which we currently don't do -- without discussing it.
> >
> > The standard says we should "write one copy of each input line on the
> > output." So, if we are being strict, we don't add a newline that isn't
> > there, because that isn't what we read. Any other interpretation
> > requires handwaving about what an "input line" even is.
>
> The System V version of uniq actually ignores the last line if it
> doesn't end in a newline. For example:
>
> $ printf "bar\nfoo\nfool" | uniq
> bar
> foo
>
> AIX, Solaris, and HP-UX still exhibit this behavior. What happens
> is that the gline() function (which reads the line) returns non-zero
> when it hits EOF, discarding any input in that line. Interestingly,
> it does realloc the line buffer as needed to handle long lines.
>
> So really, this is a corner case where you can't count on consistent
> behavior among implementations and we just need to do what we think
> is best. If you prefer we retain the existing behavior wrt a final
> line without a newline that is OK with me.
NetBSD still does what we do. So there are three behaviors in the
wild.
Sigh.
Let's go with the FreeBSD/DragonFly/GNU unconditional newline
behavior. It's simpler to implement it this way if we're going to
adopt the POSIX.1-2008 change and start ignoring newlines when we
compare lines.
We can share the blame if it breaks something.
I'll wait a few days to let other people comment, as this is a
behavior change.
Here's an updated patch. Note that we do not (yet) use the line
length for anything but stubbing out the newline so we only need
a single variable for this purpose.
OK? Objections from people who are not millert@?
Index: uniq.c
===================================================================
RCS file: /cvs/src/usr.bin/uniq/uniq.c,v
retrieving revision 1.28
diff -u -p -r1.28 uniq.c
--- uniq.c 1 Nov 2021 23:20:35 -0000 1.28
+++ uniq.c 2 Nov 2021 15:34:48 -0000
@@ -60,6 +60,7 @@ main(int argc, char *argv[])
char *prevline, *t1, *t2, *thisline;
FILE *ifp = NULL, *ofp = NULL;
size_t prevsize, thissize, tmpsize;
+ ssize_t len;
int ch;
setlocale(LC_CTYPE, "");
@@ -133,16 +134,21 @@ main(int argc, char *argv[])
prevsize = 0;
prevline = NULL;
- if (getline(&prevline, &prevsize, ifp) == -1) {
+ if ((len = getline(&prevline, &prevsize, ifp)) == -1) {
free(prevline);
if (ferror(ifp))
err(1, "getline");
exit(0);
}
+ if (prevline[len - 1] == '\n')
+ prevline[len - 1] = '\0';
thissize = 0;
thisline = NULL;
- while (getline(&thisline, &thissize, ifp) != -1) {
+ while ((len = getline(&thisline, &thissize, ifp)) != -1) {
+ if (thisline[len - 1] == '\n')
+ thisline[len - 1] = '\0';
+
/* If requested get the chosen fields + character offsets. */
if (numfields || numchars) {
t1 = skip(thisline);
@@ -185,9 +191,9 @@ show(FILE *ofp, char *str)
{
if ((dflag && repeats) || (uflag && !repeats)) {
if (cflag)
- (void)fprintf(ofp, "%4d %s", repeats + 1, str);
+ fprintf(ofp, "%4d %s\n", repeats + 1, str);
else
- (void)fprintf(ofp, "%s", str);
+ fprintf(ofp, "%s\n", str);
}
}