In uniq(1), if we use getline(3) instead of fgets(3) we can support
arbitrarily long lines.

The only potentially confusing thing here is the pointer exchange
within the loop.  The current code uses fixed buffers so we just do
a pointer swap.  Easy.

The new code uses dynamic buffers so we need to do a bit more work:
first free prevline so we don't leak it, second move thisline/thissize
to prevline/prevsize, and finally clear thisline/thissize in
preparation for the next call to getline(3).

ok?

Index: uniq.c
===================================================================
RCS file: /cvs/src/usr.bin/uniq/uniq.c,v
retrieving revision 1.27
diff -u -p -r1.27 uniq.c
--- uniq.c      31 Jul 2018 02:55:57 -0000      1.27
+++ uniq.c      1 Nov 2021 01:35:06 -0000
@@ -45,8 +45,6 @@
 #include <wchar.h>
 #include <wctype.h>
 
-#define        MAXLINELEN      (8 * 1024)
-
 int cflag, dflag, iflag, uflag;
 int numchars, numfields, repeats;
 
@@ -59,10 +57,10 @@ __dead void usage(void);
 int
 main(int argc, char *argv[])
 {
-       char *t1, *t2;
+       char *prevline, *t1, *t2, *thisline;
        FILE *ifp = NULL, *ofp = NULL;
+       size_t prevsize, thissize;
        int ch;
-       char *prevline, *thisline;
 
        setlocale(LC_CTYPE, "");
 
@@ -133,15 +131,18 @@ main(int argc, char *argv[])
        if (pledge("stdio", NULL) == -1)
                err(1, "pledge");
 
-       prevline = malloc(MAXLINELEN);
-       thisline = malloc(MAXLINELEN);
-       if (prevline == NULL || thisline == NULL)
-               err(1, "malloc");
-
-       if (fgets(prevline, MAXLINELEN, ifp) == NULL)
+       prevline = NULL;
+       prevsize = 0;
+       if (getline(&prevline, &prevsize, ifp) == -1) {
+               free(prevline);
+               if (ferror(ifp))
+                       err(1, "getline");
                exit(0);
-
-       while (fgets(thisline, MAXLINELEN, ifp)) {
+       }
+       
+       thisline = NULL;
+       thissize = 0;
+       while (getline(&thisline, &thissize, ifp) != -1) {
                /* If requested get the chosen fields + character offsets. */
                if (numfields || numchars) {
                        t1 = skip(thisline);
@@ -154,14 +155,22 @@ main(int argc, char *argv[])
                /* If different, print; set previous to new value. */
                if ((iflag ? strcasecmp : strcmp)(t1, t2)) {
                        show(ofp, prevline);
-                       t1 = prevline;
+                       free(prevline);
                        prevline = thisline;
-                       thisline = t1;
+                       prevsize = thissize;
+                       thisline = NULL;
+                       thissize = 0;
                        repeats = 0;
                } else
                        ++repeats;
        }
+       free(thisline);
+       if (ferror(ifp))
+               err(1, "getline");
+
        show(ofp, prevline);
+       free(prevline);
+
        exit(0);
 }
 

Reply via email to