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

Reply via email to