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