Anyone?
On Sat, Nov 29, 2014 at 05:40:31PM +0100, Tobias Stoeckmann wrote:
> 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);