Hi,

this diff doesn't just fix the "division by zero" for input files with
lines longer than 1023 chars in Plan B mode, it actually removes this
line limit!

Before:

$ dd if=/dev/zero bs=1 count=1024 | tr '\0' a > a
$ dd if=/dev/zero bs=1 count=1024 | tr '\0' b > b
$ diff -u a b > a.diff
$ patch -x 8 a a.diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|--- a  Sat Nov 29 17:34:15 2014
|+++ b  Sat Nov 29 17:34:19 2014
--------------------------
Floating point exception (core dumped)
$_

After:

$ patch -x 8 a a.diff
Hmm...  Looks like a unified diff to me...
The text leading up to this was:
--------------------------
|--- a  Sat Nov 29 17:34:15 2014
|+++ b  Sat Nov 29 17:34:19 2014
--------------------------
Patching file a using Plan B...
Hunk #1 succeeded at 1.
done

With this diff, patch uses fgetln to read very long lines.  One could argue
that this limits patch to the amount of RAM it has available -- but
that will happen anyway because at least twice as much memory as the
longest line has to be allocated.  fgetln is therefore a good choice to
easily parse the file.

If you want to regress-test, you can supply "-x 8" in PATCHOPTIONS to
enforce Plan B.  Keep in mind that test5 will fail because this debug
option skips a check if the input file is available.


Tobias

Index: inp.c
===================================================================
RCS file: /cvs/src/usr.bin/patch/inp.c,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 inp.c
--- inp.c       25 Nov 2014 10:22:08 -0000      1.41
+++ inp.c       29 Nov 2014 16:14:45 -0000
@@ -55,8 +55,9 @@ static char   **i_ptr;        /* pointers to line
 static int     tifd = -1;      /* plan b virtual string array */
 static char    *tibuf[2];      /* plan b buffers */
 static LINENUM tiline[2] = {-1, -1};   /* 1st line in each buffer */
-static LINENUM lines_per_buf;  /* how many lines per buffer */
-static int     tireclen;       /* length of records in tmp file */
+static size_t  lines_per_buf;  /* how many lines per buffer */
+static size_t  tibuflen;       /* plan b buffer length */
+static size_t  tireclen;       /* length of records in tmp file */
 
 static bool    rev_in_string(const char *);
 static bool    reallocate_lines(size_t *);
@@ -333,8 +334,8 @@ static void
 plan_b(const char *filename)
 {
        FILE    *ifp;
-       size_t  i = 0, j, maxlen = 1;
-       char    *p;
+       size_t  i = 0, j, len, maxlen = 1;
+       char    *lbuf = NULL, *p;
        bool    found_revision = (revision == NULL);
 
        using_plan_a = false;
@@ -343,15 +344,28 @@ plan_b(const char *filename)
        (void) unlink(TMPINNAME);
        if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0)
                pfatal("can't open file %s", TMPINNAME);
-       while (fgets(buf, sizeof buf, ifp) != NULL) {
-               if (revision != NULL && !found_revision && rev_in_string(buf))
+       while ((p = fgetln(ifp, &len)) != NULL) {
+               if (p[len - 1] == '\n')
+                       p[len - 1] = '\0';
+               else {
+                       /* EOF without EOL, copy and add the NUL */
+                       if ((lbuf = malloc(len + 1)) == NULL)
+                               fatal("out of memory\n");
+                       memcpy(lbuf, p, len);
+                       lbuf[len] = '\0';
+                       p = lbuf;
+
+                       last_line_missing_eol = true;
+                       len++;
+               }
+               if (revision != NULL && !found_revision && rev_in_string(p))
                        found_revision = true;
-               if ((i = strlen(buf)) > maxlen)
-                       maxlen = i;     /* find longest line */
+               if (len > maxlen)
+                       maxlen = len;   /* find longest line */
        }
-       last_line_missing_eol = i > 0 && buf[i - 1] != '\n';
-       if (last_line_missing_eol && maxlen == i)
-               maxlen++;
+       free(lbuf);
+       if (ferror(ifp))
+               pfatal("can't read file %s", filename);
 
        if (revision != NULL) {
                if (!found_revision) {
@@ -376,23 +390,26 @@ plan_b(const char *filename)
                            revision);
        }
        fseek(ifp, 0L, SEEK_SET);       /* rewind file */
-       lines_per_buf = BUFFERSIZE / maxlen;
        tireclen = maxlen;
-       tibuf[0] = malloc(BUFFERSIZE + 1);
+       tibuflen = maxlen > BUFFERSIZE ? maxlen : BUFFERSIZE;
+       lines_per_buf = tibuflen / maxlen;
+       tibuf[0] = malloc(tibuflen + 1);
        if (tibuf[0] == NULL)
                fatal("out of memory\n");
-       tibuf[1] = malloc(BUFFERSIZE + 1);
+       tibuf[1] = malloc(tibuflen + 1);
        if (tibuf[1] == NULL)
                fatal("out of memory\n");
        for (i = 1;; i++) {
                p = tibuf[0] + maxlen * (i % lines_per_buf);
                if (i % lines_per_buf == 0)     /* new block */
-                       if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+                       if (write(tifd, tibuf[0], tibuflen) !=
+                           (ssize_t) tibuflen)
                                pfatal("can't write temp file");
                if (fgets(p, maxlen + 1, ifp) == NULL) {
                        input_lines = i - 1;
                        if (i % lines_per_buf != 0)
-                               if (write(tifd, tibuf[0], BUFFERSIZE) < 
BUFFERSIZE)
+                               if (write(tifd, tibuf[0], tibuflen) !=
+                                   (ssize_t) tibuflen)
                                        pfatal("can't write temp file");
                        break;
                }
@@ -434,10 +451,11 @@ ifetch(LINENUM line, int whichbuf)
                        tiline[whichbuf] = baseline;
 
                        if (lseek(tifd, (off_t) (baseline / lines_per_buf *
-                           BUFFERSIZE), SEEK_SET) < 0)
+                           tibuflen), SEEK_SET) < 0)
                                pfatal("cannot seek in the temporary input 
file");
 
-                       if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
+                       if (read(tifd, tibuf[whichbuf], tibuflen)
+                           != (ssize_t) tibuflen)
                                pfatal("error reading tmp file %s", TMPINNAME);
                }
                return tibuf[whichbuf] + (tireclen * offline);

Reply via email to