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

Reply via email to