From: Ralf Thielow Date: Sat, 17 Dec 2011 18:04:14 GMT Subject: Re: [BUG] attribute "eol" with "crlf" Message-ID: In-Reply-To: <7vr504f5v5.fsf@alter.siamese.dyndns.org> Works fine for me. Thanks > Junio C Hamano writes: > >> ... >> What you said is _technically_ correct in that sense. >> >> However, I think the CRLF filter used to have a hack to strip "\r" if the >> repository data records "\r" at the end of line. This was intended to help >> people who checked in such a broken text file (if it is a text file, then >> raw ascii CR does not have a place in it in the repository representation) >> and it was a useful hack to help people recover from such mistakes to >> start the project from DOS-only world (with CRLF in the repository data) >> and migrate to cross platform world (with LF in the repository data, CRLF >> in the DOS working tree).  I suspect that the streaming filter conversion >> may not have the same hack in it. > > Perhaps something like this, but I do not use CRLF myself, so it probably > needs to be checked by extra sets of eyes. > > Thanks. > > -- >8 -- > Subject: lf_to_crlf_filter(): resurrect CRLF->CRLF hack > > The non-streaming version of the filter counts CRLF and LF in the whole > buffer, and returns without doing anything when they match (i.e. what is > recorded in the object store already uses CRLF). This was done to help > people who added files from the DOS world before realizing they want to go > cross platform and adding .gitattributes to tell Git that they only want > CRLF in their working tree. > > The streaming version of the filter does not want to read the whole thing > before starting to work, as that defeats the whole point of streaming. So > we instead check what byte follows CR whenever we see one, and add CR > before LF only when the LF does not immediately follow CR already to keep > CRLF as is. > > Signed-off-by: Junio C Hamano > --- >  convert.c |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- >  1 files changed, 50 insertions(+), 10 deletions(-) > > diff --git a/convert.c b/convert.c > index c028275..8daf4e4 100644 > --- a/convert.c > +++ b/convert.c > @@ -879,7 +879,8 @@ int is_null_stream_filter(struct stream_filter *filter) > >  struct lf_to_crlf_filter { >        struct stream_filter filter; > -       unsigned want_lf:1; > +       unsigned has_held:1; > +       char held; >  }; > >  static int lf_to_crlf_filter_fn(struct stream_filter *filter, > @@ -889,10 +890,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter, >        size_t count, o = 0; >        struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter; > > -       /* Output a pending LF if we need to */ > -       if (lf_to_crlf->want_lf) { > -               output[o++] = '\n'; > -               lf_to_crlf->want_lf = 0; > +       /* > +        * We may be holding onto the CR to see if it is followed by a > +        * LF, in which case we would need to go to the main loop. > +        * Otherwise, just emit it to the output stream. > +        */ > +       if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) { > +               output[o++] = lf_to_crlf->held; > +               lf_to_crlf->has_held = 0; >        } > >        /* We are told to drain */ > @@ -902,22 +907,57 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter, >        } > >        count = *isize_p; > -       if (count) { > +       if (count || lf_to_crlf->has_held) { >                size_t i; > +               int was_cr = 0; > + > +               if (lf_to_crlf->has_held) { > +                       was_cr = 1; > +                       lf_to_crlf->has_held = 0; > +               } > + >                for (i = 0; o < *osize_p && i < count; i++) { >                        char ch = input[i]; > + >                        if (ch == '\n') { >                                output[o++] = '\r'; > -                               if (o >= *osize_p) { > -                                       lf_to_crlf->want_lf = 1; > -                                       continue; /* We need to increase i */ > -                               } > +                       } else if (was_cr) { > +                               /* > +                                * Previous round saw CR and it is not followed > +                                * by a LF; emit the CR before processing the > +                                * current character. > +                                */ > +                               output[o++] = '\r'; >                        } > + > +                       /* > +                        * We may have consumed the last output slot, > +                        * in which case we need to break out of this > +                        * loop; hold the current character before > +                        * returning. > +                        */ > +                       if (*osize_p <= o) { > +                               lf_to_crlf->has_held = 1; > +                               lf_to_crlf->held = ch; > +                               continue; /* break but increment i */ > +                       } > + > +                       if (ch == '\r') { > +                               was_cr = 1; > +                               continue; > +                       } > + > +                       was_cr = 0; >                        output[o++] = ch; >                } > >                *osize_p -= o; >                *isize_p -= i; > + > +               if (!lf_to_crlf->has_held && was_cr) { > +                       lf_to_crlf->has_held = 1; > +                       lf_to_crlf->held = '\r'; > +               } >        } >        return 0; >  }