Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
#include "cache.h"
|
2007-04-13 13:30:05 +08:00
|
|
|
#include "attr.h"
|
2007-04-22 10:09:02 +08:00
|
|
|
#include "run-command.h"
|
2010-12-22 22:40:13 +08:00
|
|
|
#include "quote.h"
|
2012-02-21 04:53:37 +08:00
|
|
|
#include "sigchain.h"
|
2016-10-17 07:20:37 +08:00
|
|
|
#include "pkt-line.h"
|
2007-04-13 13:30:05 +08:00
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
/*
|
|
|
|
* convert.c - convert a file when checking it out and checking it in.
|
|
|
|
*
|
|
|
|
* This should use the pathname to decide on whether it wants to do some
|
|
|
|
* more interesting conversions (automatic gzip/unzip, general format
|
|
|
|
* conversions etc etc), but by default it just does automatic CRLF<->LF
|
2010-06-05 03:29:08 +08:00
|
|
|
* translation when the "text" attribute or "auto_crlf" option is set.
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
*/
|
|
|
|
|
2016-01-16 14:50:02 +08:00
|
|
|
/* Stat bits: When BIN is set, the txt bits are unset */
|
|
|
|
#define CONVERT_STAT_BITS_TXT_LF 0x1
|
|
|
|
#define CONVERT_STAT_BITS_TXT_CRLF 0x2
|
|
|
|
#define CONVERT_STAT_BITS_BIN 0x4
|
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
enum crlf_action {
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
CRLF_UNDEFINED,
|
|
|
|
CRLF_BINARY,
|
2010-05-20 04:43:10 +08:00
|
|
|
CRLF_TEXT,
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
CRLF_TEXT_INPUT,
|
|
|
|
CRLF_TEXT_CRLF,
|
|
|
|
CRLF_AUTO,
|
|
|
|
CRLF_AUTO_INPUT,
|
|
|
|
CRLF_AUTO_CRLF
|
2010-05-20 04:43:10 +08:00
|
|
|
};
|
2007-04-20 13:37:19 +08:00
|
|
|
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
struct text_stat {
|
2008-01-16 09:59:12 +08:00
|
|
|
/* NUL, CR, LF and CRLF counts */
|
2016-02-11 00:24:43 +08:00
|
|
|
unsigned nul, lonecr, lonelf, crlf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
|
|
|
/* These are just approximations! */
|
|
|
|
unsigned printable, nonprintable;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void gather_stats(const char *buf, unsigned long size, struct text_stat *stats)
|
|
|
|
{
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
memset(stats, 0, sizeof(*stats));
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) {
|
|
|
|
unsigned char c = buf[i];
|
|
|
|
if (c == '\r') {
|
2016-02-11 00:24:43 +08:00
|
|
|
if (i+1 < size && buf[i+1] == '\n') {
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
stats->crlf++;
|
2016-02-11 00:24:43 +08:00
|
|
|
i++;
|
|
|
|
} else
|
|
|
|
stats->lonecr++;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == '\n') {
|
2016-02-11 00:24:43 +08:00
|
|
|
stats->lonelf++;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == 127)
|
|
|
|
/* DEL */
|
|
|
|
stats->nonprintable++;
|
|
|
|
else if (c < 32) {
|
|
|
|
switch (c) {
|
|
|
|
/* BS, HT, ESC and FF */
|
|
|
|
case '\b': case '\t': case '\033': case '\014':
|
|
|
|
stats->printable++;
|
|
|
|
break;
|
2008-01-16 09:59:12 +08:00
|
|
|
case 0:
|
|
|
|
stats->nul++;
|
|
|
|
/* fall through */
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
default:
|
|
|
|
stats->nonprintable++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
stats->printable++;
|
|
|
|
}
|
2008-07-12 00:48:16 +08:00
|
|
|
|
|
|
|
/* If file ends with EOF then don't count this EOF as non-printable. */
|
|
|
|
if (size >= 1 && buf[size-1] == '\032')
|
|
|
|
stats->nonprintable--;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The same heuristics as diff.c::mmfile_is_binary()
|
2016-01-16 14:50:02 +08:00
|
|
|
* We treat files with bare CR as binary
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
*/
|
2016-01-16 14:50:02 +08:00
|
|
|
static int convert_is_binary(unsigned long size, const struct text_stat *stats)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
{
|
2016-02-11 00:24:43 +08:00
|
|
|
if (stats->lonecr)
|
2016-01-16 14:50:02 +08:00
|
|
|
return 1;
|
2008-01-16 09:59:12 +08:00
|
|
|
if (stats->nul)
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
if ((stats->printable >> 7) < stats->nonprintable)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-01-16 14:50:02 +08:00
|
|
|
static unsigned int gather_convert_stats(const char *data, unsigned long size)
|
|
|
|
{
|
|
|
|
struct text_stat stats;
|
2016-02-11 00:24:43 +08:00
|
|
|
int ret = 0;
|
2016-01-16 14:50:02 +08:00
|
|
|
if (!data || !size)
|
|
|
|
return 0;
|
|
|
|
gather_stats(data, size, &stats);
|
|
|
|
if (convert_is_binary(size, &stats))
|
2016-02-11 00:24:43 +08:00
|
|
|
ret |= CONVERT_STAT_BITS_BIN;
|
|
|
|
if (stats.crlf)
|
|
|
|
ret |= CONVERT_STAT_BITS_TXT_CRLF;
|
|
|
|
if (stats.lonelf)
|
|
|
|
ret |= CONVERT_STAT_BITS_TXT_LF;
|
|
|
|
|
|
|
|
return ret;
|
2016-01-16 14:50:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *gather_convert_stats_ascii(const char *data, unsigned long size)
|
|
|
|
{
|
|
|
|
unsigned int convert_stats = gather_convert_stats(data, size);
|
|
|
|
|
|
|
|
if (convert_stats & CONVERT_STAT_BITS_BIN)
|
|
|
|
return "-text";
|
|
|
|
switch (convert_stats) {
|
|
|
|
case CONVERT_STAT_BITS_TXT_LF:
|
|
|
|
return "lf";
|
|
|
|
case CONVERT_STAT_BITS_TXT_CRLF:
|
|
|
|
return "crlf";
|
|
|
|
case CONVERT_STAT_BITS_TXT_LF | CONVERT_STAT_BITS_TXT_CRLF:
|
|
|
|
return "mixed";
|
|
|
|
default:
|
|
|
|
return "none";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_cached_convert_stats_ascii(const char *path)
|
|
|
|
{
|
|
|
|
const char *ret;
|
|
|
|
unsigned long sz;
|
|
|
|
void *data = read_blob_data_from_cache(path, &sz);
|
|
|
|
ret = gather_convert_stats_ascii(data, sz);
|
|
|
|
free(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_wt_convert_stats_ascii(const char *path)
|
|
|
|
{
|
|
|
|
const char *ret = "";
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
if (strbuf_read_file(&sb, path, 0) >= 0)
|
|
|
|
ret = gather_convert_stats_ascii(sb.buf, sb.len);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-02-06 00:13:25 +08:00
|
|
|
static int text_eol_is_crlf(void)
|
|
|
|
{
|
|
|
|
if (auto_crlf == AUTO_CRLF_TRUE)
|
|
|
|
return 1;
|
|
|
|
else if (auto_crlf == AUTO_CRLF_INPUT)
|
|
|
|
return 0;
|
|
|
|
if (core_eol == EOL_CRLF)
|
|
|
|
return 1;
|
|
|
|
if (core_eol == EOL_UNSET && EOL_NATIVE == EOL_CRLF)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
static enum eol output_eol(enum crlf_action crlf_action)
|
2010-07-03 03:20:47 +08:00
|
|
|
{
|
2011-05-10 04:12:57 +08:00
|
|
|
switch (crlf_action) {
|
2010-06-05 03:29:08 +08:00
|
|
|
case CRLF_BINARY:
|
|
|
|
return EOL_UNSET;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_CRLF:
|
2010-06-05 03:29:08 +08:00
|
|
|
return EOL_CRLF;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_INPUT:
|
2010-06-05 03:29:08 +08:00
|
|
|
return EOL_LF;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_UNDEFINED:
|
|
|
|
case CRLF_AUTO_CRLF:
|
2016-06-28 16:01:13 +08:00
|
|
|
return EOL_CRLF;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_AUTO_INPUT:
|
2016-06-28 16:01:13 +08:00
|
|
|
return EOL_LF;
|
2010-06-05 03:29:08 +08:00
|
|
|
case CRLF_TEXT:
|
|
|
|
case CRLF_AUTO:
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
/* fall through */
|
2016-02-06 00:13:25 +08:00
|
|
|
return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;
|
2010-06-05 03:29:08 +08:00
|
|
|
}
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
warning("Illegal crlf_action %d\n", (int)crlf_action);
|
2011-05-10 03:52:12 +08:00
|
|
|
return core_eol;
|
2010-06-05 03:29:08 +08:00
|
|
|
}
|
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
|
2016-08-14 05:29:27 +08:00
|
|
|
struct text_stat *old_stats, struct text_stat *new_stats,
|
|
|
|
enum safe_crlf checksafe)
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
{
|
2016-08-14 05:29:27 +08:00
|
|
|
if (old_stats->crlf && !new_stats->crlf ) {
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
/*
|
2016-08-14 05:29:27 +08:00
|
|
|
* CRLFs would not be restored by checkout
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
*/
|
2016-08-14 05:29:27 +08:00
|
|
|
if (checksafe == SAFE_CRLF_WARN)
|
2016-10-17 21:15:27 +08:00
|
|
|
warning(_("CRLF will be replaced by LF in %s.\n"
|
|
|
|
"The file will have its original line"
|
|
|
|
" endings in your working directory."), path);
|
2016-08-14 05:29:27 +08:00
|
|
|
else /* i.e. SAFE_CRLF_FAIL */
|
2016-10-17 21:15:27 +08:00
|
|
|
die(_("CRLF would be replaced by LF in %s."), path);
|
2016-08-14 05:29:27 +08:00
|
|
|
} else if (old_stats->lonelf && !new_stats->lonelf ) {
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
/*
|
2016-08-14 05:29:27 +08:00
|
|
|
* CRLFs would be added by checkout
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
*/
|
2016-08-14 05:29:27 +08:00
|
|
|
if (checksafe == SAFE_CRLF_WARN)
|
2016-10-17 21:15:27 +08:00
|
|
|
warning(_("LF will be replaced by CRLF in %s.\n"
|
|
|
|
"The file will have its original line"
|
|
|
|
" endings in your working directory."), path);
|
2016-08-14 05:29:27 +08:00
|
|
|
else /* i.e. SAFE_CRLF_FAIL */
|
2016-10-17 21:15:27 +08:00
|
|
|
die(_("LF would be replaced by CRLF in %s"), path);
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
static int has_cr_in_index(const char *path)
|
|
|
|
{
|
|
|
|
unsigned long sz;
|
|
|
|
void *data;
|
|
|
|
int has_cr;
|
|
|
|
|
2013-04-13 21:28:32 +08:00
|
|
|
data = read_blob_data_from_cache(path, &sz);
|
|
|
|
if (!data)
|
autocrlf: Make it work also for un-normalized repositories
Previously, autocrlf would only work well for normalized
repositories. Any text files that contained CRLF in the repository
would cause problems, and would be modified when handled with
core.autocrlf set.
Change autocrlf to not do any conversions to files that in the
repository already contain a CR. git with autocrlf set will never
create such a file, or change a LF only file to contain CRs, so the
(new) assumption is that if a file contains a CR, it is intentional,
and autocrlf should not change that.
The following sequence should now always be a NOP even with autocrlf
set (assuming a clean working directory):
git checkout <something>
touch *
git add -A . (will add nothing)
git commit (nothing to commit)
Previously this would break for any text file containing a CR.
Some of you may have been folowing Eyvind's excellent thread about
trying to make end-of-line translation in git a bit smoother.
I decided to attack the problem from a different angle: Is it possible
to make autocrlf behave non-destructively for all the previous problem cases?
Stealing the problem from Eyvind's initial mail (paraphrased and
summarized a bit):
1. Setting autocrlf globally is a pain since autocrlf does not work well
with CRLF in the repo
2. Setting it in individual repos is hard since you do it "too late"
(the clone will get it wrong)
3. If someone checks in a file with CRLF later, you get into problems again
4. If a repository once has contained CRLF, you can't tell autocrlf
at which commit everything is sane again
5. autocrlf does needless work if you know that all your users want
the same EOL style.
I belive that this patch makes autocrlf a safe (and good) default
setting for Windows, and this solves problems 1-4 (it solves 2 by being
set by default, which is early enough for clone).
I implemented it by looking for CR charactes in the index, and
aborting any conversion attempt if this is found.
Signed-off-by: Finn Arne Gangstad <finag@pvv.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-05-12 06:37:57 +08:00
|
|
|
return 0;
|
|
|
|
has_cr = memchr(data, '\r', sz) != NULL;
|
|
|
|
free(data);
|
|
|
|
return has_cr;
|
|
|
|
}
|
|
|
|
|
2016-08-14 05:29:27 +08:00
|
|
|
static int will_convert_lf_to_crlf(size_t len, struct text_stat *stats,
|
|
|
|
enum crlf_action crlf_action)
|
|
|
|
{
|
|
|
|
if (output_eol(crlf_action) != EOL_CRLF)
|
|
|
|
return 0;
|
|
|
|
/* No "naked" LF? Nothing to convert, regardless. */
|
|
|
|
if (!stats->lonelf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
|
|
|
/* If we have any CR or CRLF line endings, we do not touch it */
|
|
|
|
/* This is the new safer autocrlf-handling */
|
|
|
|
if (stats->lonecr || stats->crlf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (convert_is_binary(len, stats))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
static int crlf_to_git(const char *path, const char *src, size_t len,
|
2011-05-10 04:12:57 +08:00
|
|
|
struct strbuf *buf,
|
|
|
|
enum crlf_action crlf_action, enum safe_crlf checksafe)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
{
|
|
|
|
struct text_stat stats;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
char *dst;
|
2016-08-14 05:29:27 +08:00
|
|
|
int convert_crlf_into_lf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
if (crlf_action == CRLF_BINARY ||
|
2012-02-25 06:05:03 +08:00
|
|
|
(src && !len))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
2012-02-25 06:05:03 +08:00
|
|
|
/*
|
|
|
|
* If we are doing a dry-run and have no source buffer, there is
|
|
|
|
* nothing to analyze; we must assume we would convert.
|
|
|
|
*/
|
|
|
|
if (!buf && !src)
|
|
|
|
return 1;
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
gather_stats(src, len, &stats);
|
2016-08-14 05:29:27 +08:00
|
|
|
/* Optimization: No CRLF? Nothing to convert, regardless. */
|
|
|
|
convert_crlf_into_lf = !!stats.crlf;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
2016-01-16 14:50:02 +08:00
|
|
|
if (convert_is_binary(len, &stats))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
2016-06-28 16:01:13 +08:00
|
|
|
/*
|
2016-12-01 01:02:32 +08:00
|
|
|
* If the file in the index has any CR in it, do not
|
|
|
|
* convert. This is the new safer autocrlf handling,
|
|
|
|
* unless we want to renormalize in a merge or
|
|
|
|
* cherry-pick.
|
2016-06-28 16:01:13 +08:00
|
|
|
*/
|
2016-12-01 01:02:32 +08:00
|
|
|
if ((checksafe != SAFE_CRLF_RENORMALIZE) && has_cr_in_index(path))
|
2016-08-14 05:29:27 +08:00
|
|
|
convert_crlf_into_lf = 0;
|
2007-04-16 04:35:45 +08:00
|
|
|
}
|
2016-12-01 01:02:32 +08:00
|
|
|
if ((checksafe == SAFE_CRLF_WARN ||
|
|
|
|
(checksafe == SAFE_CRLF_FAIL)) && len) {
|
2016-08-14 05:29:27 +08:00
|
|
|
struct text_stat new_stats;
|
|
|
|
memcpy(&new_stats, &stats, sizeof(new_stats));
|
|
|
|
/* simulate "git add" */
|
|
|
|
if (convert_crlf_into_lf) {
|
|
|
|
new_stats.lonelf += new_stats.crlf;
|
|
|
|
new_stats.crlf = 0;
|
|
|
|
}
|
|
|
|
/* simulate "git checkout" */
|
|
|
|
if (will_convert_lf_to_crlf(len, &new_stats, crlf_action)) {
|
|
|
|
new_stats.crlf += new_stats.lonelf;
|
|
|
|
new_stats.lonelf = 0;
|
|
|
|
}
|
|
|
|
check_safe_crlf(path, crlf_action, &stats, &new_stats, checksafe);
|
|
|
|
}
|
|
|
|
if (!convert_crlf_into_lf)
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
return 0;
|
|
|
|
|
2012-02-25 06:02:37 +08:00
|
|
|
/*
|
|
|
|
* At this point all of our source analysis is done, and we are sure we
|
|
|
|
* would convert. If we are in dry-run mode, we can give an answer.
|
|
|
|
*/
|
|
|
|
if (!buf)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-05 16:11:59 +08:00
|
|
|
/* only grow if not in place */
|
|
|
|
if (strbuf_avail(buf) + buf->len < len)
|
|
|
|
strbuf_grow(buf, len - buf->len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
dst = buf->buf;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (crlf_action == CRLF_AUTO || crlf_action == CRLF_AUTO_INPUT || crlf_action == CRLF_AUTO_CRLF) {
|
2007-04-20 13:37:19 +08:00
|
|
|
/*
|
|
|
|
* If we guessed, we already know we rejected a file with
|
|
|
|
* lone CR, and we can strip a CR without looking at what
|
|
|
|
* follow it.
|
|
|
|
*/
|
2007-04-16 04:35:45 +08:00
|
|
|
do {
|
2007-04-19 08:05:03 +08:00
|
|
|
unsigned char c = *src++;
|
2007-04-16 04:35:45 +08:00
|
|
|
if (c != '\r')
|
2007-04-19 08:05:03 +08:00
|
|
|
*dst++ = c;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
} while (--len);
|
2007-04-16 04:35:45 +08:00
|
|
|
} else {
|
|
|
|
do {
|
2007-04-19 08:05:03 +08:00
|
|
|
unsigned char c = *src++;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
if (! (c == '\r' && (1 < len && *src == '\n')))
|
2007-04-19 08:05:03 +08:00
|
|
|
*dst++ = c;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
} while (--len);
|
2007-04-16 04:35:45 +08:00
|
|
|
}
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_setlen(buf, dst - buf->buf);
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
static int crlf_to_worktree(const char *path, const char *src, size_t len,
|
2011-05-10 04:12:57 +08:00
|
|
|
struct strbuf *buf, enum crlf_action crlf_action)
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
{
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
char *to_free = NULL;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
struct text_stat stats;
|
|
|
|
|
2011-05-10 04:12:57 +08:00
|
|
|
if (!len || output_eol(crlf_action) != EOL_CRLF)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
gather_stats(src, len, &stats);
|
2016-08-14 05:29:27 +08:00
|
|
|
if (!will_convert_lf_to_crlf(len, &stats, crlf_action))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* are we "faking" in place editing ? */
|
|
|
|
if (src == buf->buf)
|
2007-09-27 18:58:23 +08:00
|
|
|
to_free = strbuf_detach(buf, NULL);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
|
2016-02-11 00:24:43 +08:00
|
|
|
strbuf_grow(buf, len + stats.lonelf);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
for (;;) {
|
|
|
|
const char *nl = memchr(src, '\n', len);
|
|
|
|
if (!nl)
|
|
|
|
break;
|
|
|
|
if (nl > src && nl[-1] == '\r') {
|
|
|
|
strbuf_add(buf, src, nl + 1 - src);
|
|
|
|
} else {
|
|
|
|
strbuf_add(buf, src, nl - src);
|
|
|
|
strbuf_addstr(buf, "\r\n");
|
|
|
|
}
|
|
|
|
len -= nl + 1 - src;
|
|
|
|
src = nl + 1;
|
|
|
|
}
|
|
|
|
strbuf_add(buf, src, len);
|
|
|
|
|
|
|
|
free(to_free);
|
|
|
|
return 1;
|
Lazy man's auto-CRLF
It currently does NOT know about file attributes, so it does its
conversion purely based on content. Maybe that is more in the "git
philosophy" anyway, since content is king, but I think we should try to do
the file attributes to turn it off on demand.
Anyway, BY DEFAULT it is off regardless, because it requires a
[core]
AutoCRLF = true
in your config file to be enabled. We could make that the default for
Windows, of course, the same way we do some other things (filemode etc).
But you can actually enable it on UNIX, and it will cause:
- "git update-index" will write blobs without CRLF
- "git diff" will diff working tree files without CRLF
- "git checkout" will write files to the working tree _with_ CRLF
and things work fine.
Funnily, it actually shows an odd file in git itself:
git clone -n git test-crlf
cd test-crlf
git config core.autocrlf true
git checkout
git diff
shows a diff for "Documentation/docbook-xsl.css". Why? Because we have
actually checked in that file *with* CRLF! So when "core.autocrlf" is
true, we'll always generate a *different* hash for it in the index,
because the index hash will be for the content _without_ CRLF.
Is this complete? I dunno. It seems to work for me. It doesn't use the
filename at all right now, and that's probably a deficiency (we could
certainly make the "is_binary()" heuristics also take standard filename
heuristics into account).
I don't pass in the filename at all for the "index_fd()" case
(git-update-index), so that would need to be passed around, but this
actually works fine.
NOTE NOTE NOTE! The "is_binary()" heuristics are totally made-up by yours
truly. I will not guarantee that they work at all reasonable. Caveat
emptor. But it _is_ simple, and it _is_ safe, since it's all off by
default.
The patch is pretty simple - the biggest part is the new "convert.c" file,
but even that is really just basic stuff that anybody can write in
"Teaching C 101" as a final project for their first class in programming.
Not to say that it's bug-free, of course - but at least we're not talking
about rocket surgery here.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-14 03:07:23 +08:00
|
|
|
}
|
2007-04-13 13:30:05 +08:00
|
|
|
|
2007-10-20 03:48:06 +08:00
|
|
|
struct filter_params {
|
|
|
|
const char *src;
|
|
|
|
unsigned long size;
|
2014-08-26 23:23:25 +08:00
|
|
|
int fd;
|
2007-10-20 03:48:06 +08:00
|
|
|
const char *cmd;
|
2010-12-22 22:40:13 +08:00
|
|
|
const char *path;
|
2007-10-20 03:48:06 +08:00
|
|
|
};
|
|
|
|
|
2014-08-26 23:23:25 +08:00
|
|
|
static int filter_buffer_or_fd(int in, int out, void *data)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Spawn cmd and feed the buffer contents through its stdin.
|
|
|
|
*/
|
2014-08-20 03:09:35 +08:00
|
|
|
struct child_process child_process = CHILD_PROCESS_INIT;
|
2007-10-20 03:48:06 +08:00
|
|
|
struct filter_params *params = (struct filter_params *)data;
|
2007-04-21 18:14:13 +08:00
|
|
|
int write_err, status;
|
2010-05-14 17:31:33 +08:00
|
|
|
const char *argv[] = { NULL, NULL };
|
|
|
|
|
2010-12-22 22:40:13 +08:00
|
|
|
/* apply % substitution to cmd */
|
|
|
|
struct strbuf cmd = STRBUF_INIT;
|
|
|
|
struct strbuf path = STRBUF_INIT;
|
|
|
|
struct strbuf_expand_dict_entry dict[] = {
|
|
|
|
{ "f", NULL, },
|
|
|
|
{ NULL, NULL, },
|
|
|
|
};
|
|
|
|
|
|
|
|
/* quote the path to preserve spaces, etc. */
|
|
|
|
sq_quote_buf(&path, params->path);
|
|
|
|
dict[0].value = path.buf;
|
|
|
|
|
|
|
|
/* expand all %f with the quoted path */
|
|
|
|
strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
|
|
|
|
strbuf_release(&path);
|
|
|
|
|
|
|
|
argv[0] = cmd.buf;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2007-10-20 03:47:55 +08:00
|
|
|
child_process.argv = argv;
|
2009-12-30 18:53:57 +08:00
|
|
|
child_process.use_shell = 1;
|
2007-10-20 03:47:55 +08:00
|
|
|
child_process.in = -1;
|
2010-02-06 04:57:38 +08:00
|
|
|
child_process.out = out;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2007-10-20 03:47:55 +08:00
|
|
|
if (start_command(&child_process))
|
2016-10-17 07:20:25 +08:00
|
|
|
return error("cannot fork to run external filter '%s'", params->cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2012-02-21 04:53:37 +08:00
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
2014-08-26 23:23:25 +08:00
|
|
|
if (params->src) {
|
2015-05-20 02:08:23 +08:00
|
|
|
write_err = (write_in_full(child_process.in,
|
|
|
|
params->src, params->size) < 0);
|
|
|
|
if (errno == EPIPE)
|
|
|
|
write_err = 0;
|
2014-08-26 23:23:25 +08:00
|
|
|
} else {
|
|
|
|
write_err = copy_fd(params->fd, child_process.in);
|
2015-05-20 02:08:23 +08:00
|
|
|
if (write_err == COPY_WRITE_ERROR && errno == EPIPE)
|
|
|
|
write_err = 0;
|
2014-08-26 23:23:25 +08:00
|
|
|
}
|
|
|
|
|
2007-10-20 03:47:55 +08:00
|
|
|
if (close(child_process.in))
|
2007-04-21 18:14:13 +08:00
|
|
|
write_err = 1;
|
|
|
|
if (write_err)
|
2016-10-17 07:20:25 +08:00
|
|
|
error("cannot feed the input to external filter '%s'", params->cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2012-02-21 04:53:37 +08:00
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
2007-04-21 18:14:13 +08:00
|
|
|
status = finish_command(&child_process);
|
|
|
|
if (status)
|
2016-10-17 07:20:25 +08:00
|
|
|
error("external filter '%s' failed %d", params->cmd, status);
|
2010-12-22 22:40:13 +08:00
|
|
|
|
|
|
|
strbuf_release(&cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
return (write_err || status);
|
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
static int apply_single_file_filter(const char *path, const char *src, size_t len, int fd,
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
struct strbuf *dst, const char *cmd)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Create a pipeline to have the command filter the buffer's
|
|
|
|
* contents.
|
|
|
|
*
|
|
|
|
* (child --> cmd) --> us
|
|
|
|
*/
|
2016-10-17 07:20:35 +08:00
|
|
|
int err = 0;
|
2008-10-10 03:12:12 +08:00
|
|
|
struct strbuf nbuf = STRBUF_INIT;
|
2007-10-20 03:48:06 +08:00
|
|
|
struct async async;
|
|
|
|
struct filter_params params;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2007-10-20 03:48:06 +08:00
|
|
|
memset(&async, 0, sizeof(async));
|
2014-08-26 23:23:25 +08:00
|
|
|
async.proc = filter_buffer_or_fd;
|
2007-10-20 03:48:06 +08:00
|
|
|
async.data = ¶ms;
|
2010-02-06 04:57:38 +08:00
|
|
|
async.out = -1;
|
2007-10-20 03:48:06 +08:00
|
|
|
params.src = src;
|
|
|
|
params.size = len;
|
2014-08-26 23:23:25 +08:00
|
|
|
params.fd = fd;
|
2007-10-20 03:48:06 +08:00
|
|
|
params.cmd = cmd;
|
2010-12-22 22:40:13 +08:00
|
|
|
params.path = path;
|
2007-04-21 18:14:13 +08:00
|
|
|
|
|
|
|
fflush(NULL);
|
2007-10-20 03:48:06 +08:00
|
|
|
if (start_async(&async))
|
|
|
|
return 0; /* error was already reported */
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2007-10-20 03:48:06 +08:00
|
|
|
if (strbuf_read(&nbuf, async.out, len) < 0) {
|
2016-10-17 07:20:35 +08:00
|
|
|
err = error("read from external filter '%s' failed", cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
2007-10-20 03:48:06 +08:00
|
|
|
if (close(async.out)) {
|
2016-10-17 07:20:35 +08:00
|
|
|
err = error("read from external filter '%s' failed", cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
2007-10-20 03:48:06 +08:00
|
|
|
if (finish_async(&async)) {
|
2016-10-17 07:20:35 +08:00
|
|
|
err = error("external filter '%s' failed", cmd);
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:35 +08:00
|
|
|
if (!err) {
|
2007-10-05 16:11:59 +08:00
|
|
|
strbuf_swap(dst, &nbuf);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
}
|
2007-10-05 16:11:59 +08:00
|
|
|
strbuf_release(&nbuf);
|
2016-10-17 07:20:35 +08:00
|
|
|
return !err;
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
#define CAP_CLEAN (1u<<0)
|
|
|
|
#define CAP_SMUDGE (1u<<1)
|
|
|
|
|
2017-05-05 23:27:58 +08:00
|
|
|
struct subprocess_entry {
|
2016-10-17 07:20:37 +08:00
|
|
|
struct hashmap_entry ent; /* must be the first member! */
|
|
|
|
const char *cmd;
|
|
|
|
struct child_process process;
|
|
|
|
};
|
|
|
|
|
2017-05-05 23:27:58 +08:00
|
|
|
struct cmd2process {
|
|
|
|
struct subprocess_entry subprocess; /* must be the first member! */
|
|
|
|
unsigned int supported_capabilities;
|
|
|
|
};
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
static int subprocess_map_initialized;
|
|
|
|
static struct hashmap subprocess_map;
|
2016-10-17 07:20:37 +08:00
|
|
|
|
2017-05-05 23:27:58 +08:00
|
|
|
static int cmd2process_cmp(const struct subprocess_entry *e1,
|
|
|
|
const struct subprocess_entry *e2,
|
2016-10-17 07:20:37 +08:00
|
|
|
const void *unused)
|
|
|
|
{
|
|
|
|
return strcmp(e1->cmd, e2->cmd);
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
static struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
2017-05-05 23:27:58 +08:00
|
|
|
struct subprocess_entry key;
|
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
hashmap_entry_init(&key, strhash(cmd));
|
|
|
|
key.cmd = cmd;
|
|
|
|
return hashmap_get(hashmap, &key, NULL);
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
static void subprocess_read_status(int fd, struct strbuf *status)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
|
|
|
struct strbuf **pair;
|
|
|
|
char *line;
|
|
|
|
for (;;) {
|
|
|
|
line = packet_read_line(fd, NULL);
|
|
|
|
if (!line)
|
|
|
|
break;
|
|
|
|
pair = strbuf_split_str(line, '=', 2);
|
|
|
|
if (pair[0] && pair[0]->len && pair[1]) {
|
|
|
|
/* the last "status=<foo>" line wins */
|
|
|
|
if (!strcmp(pair[0]->buf, "status=")) {
|
|
|
|
strbuf_reset(status);
|
|
|
|
strbuf_addbuf(status, pair[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strbuf_list_free(pair);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
static void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
|
|
|
if (!entry)
|
|
|
|
return;
|
|
|
|
|
|
|
|
entry->process.clean_on_exit = 0;
|
|
|
|
kill(entry->process.pid, SIGTERM);
|
|
|
|
finish_command(&entry->process);
|
|
|
|
|
|
|
|
hashmap_remove(hashmap, entry, NULL);
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
static void subprocess_exit_handler(struct child_process *process)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
2017-05-05 23:28:00 +08:00
|
|
|
/* Closing the pipe signals the subprocess to initiate a shutdown. */
|
2016-10-17 07:20:37 +08:00
|
|
|
close(process->in);
|
|
|
|
close(process->out);
|
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
/* Finish command will wait until the shutdown is complete. */
|
|
|
|
finish_command(process);
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:27:59 +08:00
|
|
|
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
|
2016-10-17 07:20:37 +08:00
|
|
|
{
|
|
|
|
int err;
|
2017-05-05 23:27:59 +08:00
|
|
|
struct cmd2process *entry = (struct cmd2process *)subprocess;
|
2016-10-17 07:20:37 +08:00
|
|
|
struct string_list cap_list = STRING_LIST_INIT_NODUP;
|
|
|
|
char *cap_buf;
|
|
|
|
const char *cap_name;
|
2017-05-05 23:27:59 +08:00
|
|
|
struct child_process *process = &subprocess->process;
|
|
|
|
const char *cmd = subprocess->cmd;
|
2016-10-17 07:20:37 +08:00
|
|
|
|
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
2017-05-05 23:27:56 +08:00
|
|
|
err = packet_writel(process->in, "git-filter-client", "version=2", NULL);
|
2016-10-17 07:20:37 +08:00
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = strcmp(packet_read_line(process->out, NULL), "git-filter-server");
|
|
|
|
if (err) {
|
|
|
|
error("external filter '%s' does not support filter protocol version 2", cmd);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
err = strcmp(packet_read_line(process->out, NULL), "version=2");
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
err = packet_read_line(process->out, NULL) != NULL;
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-05-05 23:27:56 +08:00
|
|
|
err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL);
|
2016-10-17 07:20:37 +08:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
cap_buf = packet_read_line(process->out, NULL);
|
|
|
|
if (!cap_buf)
|
|
|
|
break;
|
|
|
|
string_list_split_in_place(&cap_list, cap_buf, '=', 1);
|
|
|
|
|
|
|
|
if (cap_list.nr != 2 || strcmp(cap_list.items[0].string, "capability"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cap_name = cap_list.items[1].string;
|
|
|
|
if (!strcmp(cap_name, "clean")) {
|
|
|
|
entry->supported_capabilities |= CAP_CLEAN;
|
|
|
|
} else if (!strcmp(cap_name, "smudge")) {
|
|
|
|
entry->supported_capabilities |= CAP_SMUDGE;
|
|
|
|
} else {
|
|
|
|
warning(
|
|
|
|
"external filter '%s' requested unsupported filter capability '%s'",
|
|
|
|
cmd, cap_name
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
string_list_clear(&cap_list, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
2017-05-05 23:27:57 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-05-05 23:27:59 +08:00
|
|
|
typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
|
2017-05-05 23:28:00 +08:00
|
|
|
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
|
2017-05-05 23:27:59 +08:00
|
|
|
subprocess_start_fn startfn)
|
2017-05-05 23:27:57 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct child_process *process;
|
|
|
|
const char *argv[] = { cmd, NULL };
|
|
|
|
|
2017-05-05 23:27:59 +08:00
|
|
|
entry->cmd = cmd;
|
|
|
|
process = &entry->process;
|
2017-05-05 23:27:57 +08:00
|
|
|
|
|
|
|
child_process_init(process);
|
|
|
|
process->argv = argv;
|
|
|
|
process->use_shell = 1;
|
|
|
|
process->in = -1;
|
|
|
|
process->out = -1;
|
|
|
|
process->clean_on_exit = 1;
|
2017-05-05 23:28:00 +08:00
|
|
|
process->clean_on_exit_handler = subprocess_exit_handler;
|
2017-05-05 23:27:57 +08:00
|
|
|
|
2017-05-05 23:27:59 +08:00
|
|
|
err = start_command(process);
|
|
|
|
if (err) {
|
2017-05-05 23:28:00 +08:00
|
|
|
error("cannot fork to run subprocess '%s'", cmd);
|
2017-05-05 23:27:59 +08:00
|
|
|
return err;
|
2017-05-05 23:27:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
hashmap_entry_init(entry, strhash(cmd));
|
|
|
|
|
2017-05-05 23:27:59 +08:00
|
|
|
err = startfn(entry);
|
2017-05-05 23:27:53 +08:00
|
|
|
if (err) {
|
2017-05-05 23:28:00 +08:00
|
|
|
error("initialization for subprocess '%s' failed", cmd);
|
|
|
|
subprocess_stop(hashmap, entry);
|
2017-05-05 23:27:59 +08:00
|
|
|
return err;
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
hashmap_add(hashmap, entry);
|
2017-05-05 23:27:59 +08:00
|
|
|
return 0;
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int apply_multi_file_filter(const char *path, const char *src, size_t len,
|
|
|
|
int fd, struct strbuf *dst, const char *cmd,
|
|
|
|
const unsigned int wanted_capability)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
struct cmd2process *entry;
|
|
|
|
struct child_process *process;
|
|
|
|
struct strbuf nbuf = STRBUF_INIT;
|
|
|
|
struct strbuf filter_status = STRBUF_INIT;
|
|
|
|
const char *filter_type;
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
if (!subprocess_map_initialized) {
|
|
|
|
subprocess_map_initialized = 1;
|
|
|
|
hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp, 0);
|
2016-10-17 07:20:37 +08:00
|
|
|
entry = NULL;
|
|
|
|
} else {
|
2017-05-05 23:28:00 +08:00
|
|
|
entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fflush(NULL);
|
|
|
|
|
|
|
|
if (!entry) {
|
2017-05-05 23:27:59 +08:00
|
|
|
entry = xmalloc(sizeof(*entry));
|
|
|
|
entry->supported_capabilities = 0;
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
if (subprocess_start(&subprocess_map, &entry->subprocess, cmd, start_multi_file_filter_fn)) {
|
2017-05-05 23:27:59 +08:00
|
|
|
free(entry);
|
2016-10-17 07:20:37 +08:00
|
|
|
return 0;
|
2017-05-05 23:27:59 +08:00
|
|
|
}
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
2017-05-05 23:27:58 +08:00
|
|
|
process = &entry->subprocess.process;
|
2016-10-17 07:20:37 +08:00
|
|
|
|
|
|
|
if (!(wanted_capability & entry->supported_capabilities))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (CAP_CLEAN & wanted_capability)
|
|
|
|
filter_type = "clean";
|
|
|
|
else if (CAP_SMUDGE & wanted_capability)
|
|
|
|
filter_type = "smudge";
|
|
|
|
else
|
|
|
|
die("unexpected filter type");
|
|
|
|
|
|
|
|
sigchain_push(SIGPIPE, SIG_IGN);
|
|
|
|
|
|
|
|
assert(strlen(filter_type) < LARGE_PACKET_DATA_MAX - strlen("command=\n"));
|
|
|
|
err = packet_write_fmt_gently(process->in, "command=%s\n", filter_type);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = strlen(path) > LARGE_PACKET_DATA_MAX - strlen("pathname=\n");
|
|
|
|
if (err) {
|
|
|
|
error("path name too long for external filter");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = packet_write_fmt_gently(process->in, "pathname=%s\n", path);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = packet_flush_gently(process->in);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (fd >= 0)
|
|
|
|
err = write_packetized_from_fd(fd, process->in);
|
|
|
|
else
|
|
|
|
err = write_packetized_from_buf(src, len, process->in);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
subprocess_read_status(process->out, &filter_status);
|
2016-10-17 07:20:37 +08:00
|
|
|
err = strcmp(filter_status.buf, "success");
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
err = read_packetized_to_strbuf(process->out, &nbuf) < 0;
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2017-05-05 23:28:00 +08:00
|
|
|
subprocess_read_status(process->out, &filter_status);
|
2016-10-17 07:20:37 +08:00
|
|
|
err = strcmp(filter_status.buf, "success");
|
|
|
|
|
|
|
|
done:
|
|
|
|
sigchain_pop(SIGPIPE);
|
|
|
|
|
2017-05-05 23:27:53 +08:00
|
|
|
if (err) {
|
2016-10-17 07:20:37 +08:00
|
|
|
if (!strcmp(filter_status.buf, "error")) {
|
|
|
|
/* The filter signaled a problem with the file. */
|
|
|
|
} else if (!strcmp(filter_status.buf, "abort")) {
|
|
|
|
/*
|
|
|
|
* The filter signaled a permanent problem. Don't try to filter
|
|
|
|
* files with the same command for the lifetime of the current
|
|
|
|
* Git process.
|
|
|
|
*/
|
|
|
|
entry->supported_capabilities &= ~wanted_capability;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Something went wrong with the protocol filter.
|
|
|
|
* Force shutdown and restart if another blob requires filtering.
|
|
|
|
*/
|
|
|
|
error("external filter '%s' failed", cmd);
|
2017-05-05 23:28:00 +08:00
|
|
|
subprocess_stop(&subprocess_map, &entry->subprocess);
|
2017-05-05 23:27:59 +08:00
|
|
|
free(entry);
|
2016-10-17 07:20:37 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
strbuf_swap(dst, &nbuf);
|
|
|
|
}
|
|
|
|
strbuf_release(&nbuf);
|
|
|
|
return !err;
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct convert_driver {
|
|
|
|
const char *name;
|
|
|
|
struct convert_driver *next;
|
2008-07-05 13:24:42 +08:00
|
|
|
const char *smudge;
|
|
|
|
const char *clean;
|
2016-10-17 07:20:37 +08:00
|
|
|
const char *process;
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
int required;
|
2007-04-21 18:14:13 +08:00
|
|
|
} *user_convert, **user_convert_tail;
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
static int apply_filter(const char *path, const char *src, size_t len,
|
|
|
|
int fd, struct strbuf *dst, struct convert_driver *drv,
|
|
|
|
const unsigned int wanted_capability)
|
|
|
|
{
|
|
|
|
const char *cmd = NULL;
|
|
|
|
|
|
|
|
if (!drv)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!dst)
|
|
|
|
return 1;
|
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
if ((CAP_CLEAN & wanted_capability) && !drv->process && drv->clean)
|
2016-10-17 07:20:36 +08:00
|
|
|
cmd = drv->clean;
|
2016-10-17 07:20:37 +08:00
|
|
|
else if ((CAP_SMUDGE & wanted_capability) && !drv->process && drv->smudge)
|
2016-10-17 07:20:36 +08:00
|
|
|
cmd = drv->smudge;
|
|
|
|
|
|
|
|
if (cmd && *cmd)
|
|
|
|
return apply_single_file_filter(path, src, len, fd, dst, cmd);
|
2016-10-17 07:20:37 +08:00
|
|
|
else if (drv->process && *drv->process)
|
|
|
|
return apply_multi_file_filter(path, src, len, fd, dst, drv->process, wanted_capability);
|
2016-10-17 07:20:36 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-15 01:46:53 +08:00
|
|
|
static int read_convert_config(const char *var, const char *value, void *cb)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
2013-01-23 14:24:23 +08:00
|
|
|
const char *key, *name;
|
2007-04-21 18:14:13 +08:00
|
|
|
int namelen;
|
|
|
|
struct convert_driver *drv;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* External conversion drivers are configured using
|
|
|
|
* "filter.<name>.variable".
|
|
|
|
*/
|
2013-01-23 14:24:23 +08:00
|
|
|
if (parse_config_key(var, "filter", &name, &namelen, &key) < 0 || !name)
|
2007-04-21 18:14:13 +08:00
|
|
|
return 0;
|
|
|
|
for (drv = user_convert; drv; drv = drv->next)
|
|
|
|
if (!strncmp(drv->name, name, namelen) && !drv->name[namelen])
|
|
|
|
break;
|
|
|
|
if (!drv) {
|
|
|
|
drv = xcalloc(1, sizeof(struct convert_driver));
|
2007-09-16 06:32:36 +08:00
|
|
|
drv->name = xmemdupz(name, namelen);
|
2007-04-21 18:14:13 +08:00
|
|
|
*user_convert_tail = drv;
|
|
|
|
user_convert_tail = &(drv->next);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* filter.<name>.smudge and filter.<name>.clean specifies
|
|
|
|
* the command line:
|
|
|
|
*
|
|
|
|
* command-line
|
|
|
|
*
|
|
|
|
* The command-line will not be interpolated in any way.
|
|
|
|
*/
|
|
|
|
|
2013-01-23 14:24:23 +08:00
|
|
|
if (!strcmp("smudge", key))
|
2008-07-05 13:24:42 +08:00
|
|
|
return git_config_string(&drv->smudge, var, value);
|
|
|
|
|
2013-01-23 14:24:23 +08:00
|
|
|
if (!strcmp("clean", key))
|
2008-07-05 13:24:42 +08:00
|
|
|
return git_config_string(&drv->clean, var, value);
|
2007-04-21 18:14:13 +08:00
|
|
|
|
2016-10-17 07:20:37 +08:00
|
|
|
if (!strcmp("process", key))
|
|
|
|
return git_config_string(&drv->process, var, value);
|
|
|
|
|
2013-01-23 14:24:23 +08:00
|
|
|
if (!strcmp("required", key)) {
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
drv->required = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-21 18:14:13 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-22 10:09:02 +08:00
|
|
|
static int count_ident(const char *cp, unsigned long size)
|
|
|
|
{
|
|
|
|
/*
|
2007-05-14 21:37:25 +08:00
|
|
|
* "$Id: 0000000000000000000000000000000000000000 $" <=> "$Id$"
|
2007-04-22 10:09:02 +08:00
|
|
|
*/
|
|
|
|
int cnt = 0;
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
while (size) {
|
|
|
|
ch = *cp++;
|
|
|
|
size--;
|
|
|
|
if (ch != '$')
|
|
|
|
continue;
|
2007-05-14 21:37:25 +08:00
|
|
|
if (size < 3)
|
2007-04-22 10:09:02 +08:00
|
|
|
break;
|
2007-05-14 21:37:25 +08:00
|
|
|
if (memcmp("Id", cp, 2))
|
2007-04-22 10:09:02 +08:00
|
|
|
continue;
|
2007-05-14 21:37:25 +08:00
|
|
|
ch = cp[2];
|
|
|
|
cp += 3;
|
|
|
|
size -= 3;
|
2007-04-22 10:09:02 +08:00
|
|
|
if (ch == '$')
|
2007-05-14 21:37:25 +08:00
|
|
|
cnt++; /* $Id$ */
|
2007-04-22 10:09:02 +08:00
|
|
|
if (ch != ':')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
2007-05-14 21:37:25 +08:00
|
|
|
* "$Id: ... "; scan up to the closing dollar sign and discard.
|
2007-04-22 10:09:02 +08:00
|
|
|
*/
|
|
|
|
while (size) {
|
|
|
|
ch = *cp++;
|
|
|
|
size--;
|
|
|
|
if (ch == '$') {
|
|
|
|
cnt++;
|
|
|
|
break;
|
|
|
|
}
|
2010-04-06 20:46:37 +08:00
|
|
|
if (ch == '\n')
|
|
|
|
break;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
static int ident_to_git(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *buf, int ident)
|
2007-04-22 10:09:02 +08:00
|
|
|
{
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
char *dst, *dollar;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
2012-02-25 06:05:03 +08:00
|
|
|
if (!ident || (src && !count_ident(src, len)))
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
|
|
|
|
2012-02-25 06:02:37 +08:00
|
|
|
if (!buf)
|
|
|
|
return 1;
|
|
|
|
|
2007-10-05 16:11:59 +08:00
|
|
|
/* only grow if not in place */
|
|
|
|
if (strbuf_avail(buf) + buf->len < len)
|
|
|
|
strbuf_grow(buf, len - buf->len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
dst = buf->buf;
|
|
|
|
for (;;) {
|
|
|
|
dollar = memchr(src, '$', len);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
2011-08-30 04:06:04 +08:00
|
|
|
memmove(dst, src, dollar + 1 - src);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
dst += dollar + 1 - src;
|
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
|
|
|
|
|
|
|
if (len > 3 && !memcmp(src, "Id:", 3)) {
|
|
|
|
dollar = memchr(src + 3, '$', len - 3);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
2010-04-06 20:46:37 +08:00
|
|
|
if (memchr(src + 3, '\n', dollar - src - 3)) {
|
|
|
|
/* Line break before the next dollar. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-05-14 21:37:25 +08:00
|
|
|
memcpy(dst, "Id$", 3);
|
|
|
|
dst += 3;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
|
|
|
}
|
2011-08-30 04:06:04 +08:00
|
|
|
memmove(dst, src, len);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_setlen(buf, dst + len - buf->buf);
|
|
|
|
return 1;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
static int ident_to_worktree(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *buf, int ident)
|
2007-04-22 10:09:02 +08:00
|
|
|
{
|
|
|
|
unsigned char sha1[20];
|
2010-04-06 20:46:38 +08:00
|
|
|
char *to_free = NULL, *dollar, *spc;
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
int cnt;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
|
|
|
if (!ident)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
cnt = count_ident(src, len);
|
2007-04-22 10:09:02 +08:00
|
|
|
if (!cnt)
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
return 0;
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* are we "faking" in place editing ? */
|
|
|
|
if (src == buf->buf)
|
2007-09-27 18:58:23 +08:00
|
|
|
to_free = strbuf_detach(buf, NULL);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
hash_sha1_file(src, len, "blob", sha1);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_grow(buf, len + cnt * 43);
|
|
|
|
for (;;) {
|
|
|
|
/* step 1: run to the next '$' */
|
|
|
|
dollar = memchr(src, '$', len);
|
|
|
|
if (!dollar)
|
|
|
|
break;
|
|
|
|
strbuf_add(buf, src, dollar + 1 - src);
|
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 18:50:08 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* step 2: does it looks like a bit like Id:xxx$ or Id$ ? */
|
|
|
|
if (len < 3 || memcmp("Id", src, 2))
|
2007-04-22 10:09:02 +08:00
|
|
|
continue;
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* step 3: skip over Id$ or Id:xxxxx$ */
|
|
|
|
if (src[2] == '$') {
|
|
|
|
src += 3;
|
|
|
|
len -= 3;
|
|
|
|
} else if (src[2] == ':') {
|
|
|
|
/*
|
|
|
|
* It's possible that an expanded Id has crept its way into the
|
2010-04-06 20:46:38 +08:00
|
|
|
* repository, we cope with that by stripping the expansion out.
|
|
|
|
* This is probably not a good idea, since it will cause changes
|
|
|
|
* on checkout, which won't go away by stash, but let's keep it
|
|
|
|
* for git-style ids.
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
*/
|
|
|
|
dollar = memchr(src + 3, '$', len - 3);
|
|
|
|
if (!dollar) {
|
|
|
|
/* incomplete keyword, no more '$', so just quit the loop */
|
|
|
|
break;
|
|
|
|
}
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 18:50:08 +08:00
|
|
|
|
2010-04-06 20:46:37 +08:00
|
|
|
if (memchr(src + 3, '\n', dollar - src - 3)) {
|
|
|
|
/* Line break before the next dollar. */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-04-06 20:46:38 +08:00
|
|
|
spc = memchr(src + 4, ' ', dollar - src - 4);
|
|
|
|
if (spc && spc < dollar-1) {
|
|
|
|
/* There are spaces in unexpected places.
|
|
|
|
* This is probably an id from some other
|
|
|
|
* versioning system. Keep it for now.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
len -= dollar + 1 - src;
|
|
|
|
src = dollar + 1;
|
|
|
|
} else {
|
|
|
|
/* it wasn't a "Id$" or "Id:xxxx$" */
|
|
|
|
continue;
|
|
|
|
}
|
Fix mishandling of $Id$ expanded in the repository copy in convert.c
If the repository contained an expanded ident keyword (i.e. $Id:XXXX$),
then the wrong bytes were discarded, and the Id keyword was not
expanded. The fault was in convert.c:ident_to_worktree().
Previously, when a "$Id:" was found in the repository version,
ident_to_worktree() would search for the next "$" after this, and
discarded everything it found until then. That was done with the loop:
do {
ch = *cp++;
if (ch == '$')
break;
rem--;
} while (rem);
The above loop left cp pointing one character _after_ the final "$"
(because of ch = *cp++). This was different from the non-expanded case,
were cp is left pointing at the "$", and was different from the comment
which stated "discard up to but not including the closing $". This
patch fixes that by making the loop:
do {
ch = *cp;
if (ch == '$')
break;
cp++;
rem--;
} while (rem);
That is, cp is tested _then_ incremented.
This loop exits if it finds a "$" or if it runs out of bytes in the
source. After this loop, if there was no closing "$" the expansion is
skipped, and the outer loop is allowed to continue leaving this
non-keyword as it was. However, when the "$" is found, size is
corrected, before running the expansion:
size -= (cp - src);
This is wrong; size is going to be corrected anyway after the expansion,
so there is no need to do it here. This patch removes that redundant
correction.
To help find this bug, I heavily commented the routine; those comments
are included here as a bonus.
Signed-off-by: Andy Parkins <andyparkins@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-25 18:50:08 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
/* step 4: substitute */
|
|
|
|
strbuf_addstr(buf, "Id: ");
|
|
|
|
strbuf_add(buf, sha1_to_hex(sha1), 40);
|
|
|
|
strbuf_addstr(buf, " $");
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
strbuf_add(buf, src, len);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
free(to_free);
|
|
|
|
return 1;
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static enum crlf_action git_path_check_crlf(struct attr_check_item *check)
|
2007-04-13 13:30:05 +08:00
|
|
|
{
|
2007-04-21 14:44:02 +08:00
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value))
|
|
|
|
return CRLF_TEXT;
|
|
|
|
else if (ATTR_FALSE(value))
|
|
|
|
return CRLF_BINARY;
|
|
|
|
else if (ATTR_UNSET(value))
|
|
|
|
;
|
|
|
|
else if (!strcmp(value, "input"))
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
return CRLF_TEXT_INPUT;
|
2010-05-20 04:43:10 +08:00
|
|
|
else if (!strcmp(value, "auto"))
|
|
|
|
return CRLF_AUTO;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
return CRLF_UNDEFINED;
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static enum eol git_path_check_eol(struct attr_check_item *check)
|
2010-05-20 04:43:10 +08:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
if (ATTR_UNSET(value))
|
|
|
|
;
|
|
|
|
else if (!strcmp(value, "lf"))
|
|
|
|
return EOL_LF;
|
|
|
|
else if (!strcmp(value, "crlf"))
|
|
|
|
return EOL_CRLF;
|
|
|
|
return EOL_UNSET;
|
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static struct convert_driver *git_path_check_convert(struct attr_check_item *check)
|
2007-04-21 18:14:13 +08:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
struct convert_driver *drv;
|
|
|
|
|
|
|
|
if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
|
|
|
|
return NULL;
|
|
|
|
for (drv = user_convert; drv; drv = drv->next)
|
|
|
|
if (!strcmp(value, drv->name))
|
|
|
|
return drv;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-01-28 10:01:54 +08:00
|
|
|
static int git_path_check_ident(struct attr_check_item *check)
|
2007-04-22 10:09:02 +08:00
|
|
|
{
|
|
|
|
const char *value = check->value;
|
|
|
|
|
|
|
|
return !!ATTR_TRUE(value);
|
|
|
|
}
|
|
|
|
|
2011-05-10 04:58:31 +08:00
|
|
|
struct conv_attrs {
|
|
|
|
struct convert_driver *drv;
|
2016-02-06 00:13:23 +08:00
|
|
|
enum crlf_action attr_action; /* What attr says */
|
|
|
|
enum crlf_action crlf_action; /* When no attr is set, use core.autocrlf */
|
2011-05-10 04:58:31 +08:00
|
|
|
int ident;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void convert_attrs(struct conv_attrs *ca, const char *path)
|
2011-05-10 02:23:04 +08:00
|
|
|
{
|
2017-01-28 10:01:57 +08:00
|
|
|
static struct attr_check *check;
|
2011-05-10 02:23:04 +08:00
|
|
|
|
2017-01-28 10:01:57 +08:00
|
|
|
if (!check) {
|
|
|
|
check = attr_check_initl("crlf", "ident", "filter",
|
|
|
|
"eol", "text", NULL);
|
2011-05-10 02:23:04 +08:00
|
|
|
user_convert_tail = &user_convert;
|
|
|
|
git_config(read_convert_config, NULL);
|
|
|
|
}
|
2011-05-10 04:58:31 +08:00
|
|
|
|
2017-01-28 10:01:57 +08:00
|
|
|
if (!git_check_attr(path, check)) {
|
|
|
|
struct attr_check_item *ccheck = check->items;
|
2016-02-06 00:13:23 +08:00
|
|
|
ca->crlf_action = git_path_check_crlf(ccheck + 4);
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED)
|
2016-02-06 00:13:22 +08:00
|
|
|
ca->crlf_action = git_path_check_crlf(ccheck + 0);
|
2016-02-06 00:13:23 +08:00
|
|
|
ca->attr_action = ca->crlf_action;
|
2016-02-06 00:13:22 +08:00
|
|
|
ca->ident = git_path_check_ident(ccheck + 1);
|
|
|
|
ca->drv = git_path_check_convert(ccheck + 2);
|
2016-02-24 01:07:19 +08:00
|
|
|
if (ca->crlf_action != CRLF_BINARY) {
|
|
|
|
enum eol eol_attr = git_path_check_eol(ccheck + 3);
|
2016-06-28 16:01:13 +08:00
|
|
|
if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_LF)
|
|
|
|
ca->crlf_action = CRLF_AUTO_INPUT;
|
|
|
|
else if (ca->crlf_action == CRLF_AUTO && eol_attr == EOL_CRLF)
|
|
|
|
ca->crlf_action = CRLF_AUTO_CRLF;
|
|
|
|
else if (eol_attr == EOL_LF)
|
2016-02-24 01:07:19 +08:00
|
|
|
ca->crlf_action = CRLF_TEXT_INPUT;
|
|
|
|
else if (eol_attr == EOL_CRLF)
|
|
|
|
ca->crlf_action = CRLF_TEXT_CRLF;
|
|
|
|
}
|
|
|
|
ca->attr_action = ca->crlf_action;
|
2011-05-10 04:58:31 +08:00
|
|
|
} else {
|
|
|
|
ca->drv = NULL;
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
ca->crlf_action = CRLF_UNDEFINED;
|
2011-05-10 04:58:31 +08:00
|
|
|
ca->ident = 0;
|
|
|
|
}
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
if (ca->crlf_action == CRLF_TEXT)
|
|
|
|
ca->crlf_action = text_eol_is_crlf() ? CRLF_TEXT_CRLF : CRLF_TEXT_INPUT;
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_FALSE)
|
|
|
|
ca->crlf_action = CRLF_BINARY;
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_TRUE)
|
|
|
|
ca->crlf_action = CRLF_AUTO_CRLF;
|
|
|
|
if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_INPUT)
|
|
|
|
ca->crlf_action = CRLF_AUTO_INPUT;
|
2011-05-10 02:23:04 +08:00
|
|
|
}
|
|
|
|
|
2014-08-26 23:23:25 +08:00
|
|
|
int would_convert_to_git_filter_fd(const char *path)
|
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
|
|
|
|
convert_attrs(&ca, path);
|
|
|
|
if (!ca.drv)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply a filter to an fd only if the filter is required to succeed.
|
|
|
|
* We must die if the filter fails, because the original data before
|
|
|
|
* filtering is not available.
|
|
|
|
*/
|
|
|
|
if (!ca.drv->required)
|
|
|
|
return 0;
|
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN);
|
2014-08-26 23:23:25 +08:00
|
|
|
}
|
|
|
|
|
2016-01-16 14:50:02 +08:00
|
|
|
const char *get_convert_attr_ascii(const char *path)
|
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
|
|
|
|
convert_attrs(&ca, path);
|
2016-02-06 00:13:23 +08:00
|
|
|
switch (ca.attr_action) {
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_UNDEFINED:
|
2016-01-16 14:50:02 +08:00
|
|
|
return "";
|
|
|
|
case CRLF_BINARY:
|
|
|
|
return "-text";
|
|
|
|
case CRLF_TEXT:
|
|
|
|
return "text";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_INPUT:
|
2016-01-16 14:50:02 +08:00
|
|
|
return "text eol=lf";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_TEXT_CRLF:
|
|
|
|
return "text eol=crlf";
|
2016-01-16 14:50:02 +08:00
|
|
|
case CRLF_AUTO:
|
|
|
|
return "text=auto";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_AUTO_CRLF:
|
2016-06-28 16:01:13 +08:00
|
|
|
return "text=auto eol=crlf";
|
convert.c: refactor crlf_action
Refactor the determination and usage of crlf_action.
Today, when no "crlf" attribute are set on a file, crlf_action is set to
CRLF_GUESS. Use CRLF_UNDEFINED instead, and search for "text" or "eol" as
before.
After searching for line ending attributes, save the value in
struct conv_attrs.crlf_action attr_action,
so that get_convert_attr_ascii() is able report the attributes.
Replace the old CRLF_GUESS usage:
CRLF_GUESS && core.autocrlf=true -> CRLF_AUTO_CRLF
CRLF_GUESS && core.autocrlf=false -> CRLF_BINARY
CRLF_GUESS && core.autocrlf=input -> CRLF_AUTO_INPUT
Save the action in conv_attrs.crlf_action (as before) and change
all callers.
Make more clear, what is what, by defining:
- CRLF_UNDEFINED : No attributes set. Temparally used, until core.autocrlf
and core.eol is evaluated and one of CRLF_BINARY,
CRLF_AUTO_INPUT or CRLF_AUTO_CRLF is selected
- CRLF_BINARY : No processing of line endings.
- CRLF_TEXT : attribute "text" is set, line endings are processed.
- CRLF_TEXT_INPUT: attribute "input" or "eol=lf" is set. This implies text.
- CRLF_TEXT_CRLF : attribute "eol=crlf" is set. This implies text.
- CRLF_AUTO : attribute "auto" is set.
- CRLF_AUTO_INPUT: core.autocrlf=input (no attributes)
- CRLF_AUTO_CRLF : core.autocrlf=true (no attributes)
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-02-11 00:24:41 +08:00
|
|
|
case CRLF_AUTO_INPUT:
|
2016-06-28 16:01:13 +08:00
|
|
|
return "text=auto eol=lf";
|
2016-01-16 14:50:02 +08:00
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
safecrlf: Add mechanism to warn about irreversible crlf conversions
CRLF conversion bears a slight chance of corrupting data.
autocrlf=true will convert CRLF to LF during commit and LF to
CRLF during checkout. A file that contains a mixture of LF and
CRLF before the commit cannot be recreated by git. For text
files this is the right thing to do: it corrects line endings
such that we have only LF line endings in the repository.
But for binary files that are accidentally classified as text the
conversion can corrupt data.
If you recognize such corruption early you can easily fix it by
setting the conversion type explicitly in .gitattributes. Right
after committing you still have the original file in your work
tree and this file is not yet corrupted. You can explicitly tell
git that this file is binary and git will handle the file
appropriately.
Unfortunately, the desired effect of cleaning up text files with
mixed line endings and the undesired effect of corrupting binary
files cannot be distinguished. In both cases CRLFs are removed
in an irreversible way. For text files this is the right thing
to do because CRLFs are line endings, while for binary files
converting CRLFs corrupts data.
This patch adds a mechanism that can either warn the user about
an irreversible conversion or can even refuse to convert. The
mechanism is controlled by the variable core.safecrlf, with the
following values:
- false: disable safecrlf mechanism
- warn: warn about irreversible conversions
- true: refuse irreversible conversions
The default is to warn. Users are only affected by this default
if core.autocrlf is set. But the current default of git is to
leave core.autocrlf unset, so users will not see warnings unless
they deliberately chose to activate the autocrlf mechanism.
The safecrlf mechanism's details depend on the git command. The
general principles when safecrlf is active (not false) are:
- we warn/error out if files in the work tree can modified in an
irreversible way without giving the user a chance to backup the
original file.
- for read-only operations that do not modify files in the work tree
we do not not print annoying warnings.
There are exceptions. Even though...
- "git add" itself does not touch the files in the work tree, the
next checkout would, so the safety triggers;
- "git apply" to update a text file with a patch does touch the files
in the work tree, but the operation is about text files and CRLF
conversion is about fixing the line ending inconsistencies, so the
safety does not trigger;
- "git diff" itself does not touch the files in the work tree, it is
often run to inspect the changes you intend to next "git add". To
catch potential problems early, safety triggers.
The concept of a safety check was originally proposed in a similar
way by Linus Torvalds. Thanks to Dimitry Potapov for insisting
on getting the naked LF/autocrlf=true case right.
Signed-off-by: Steffen Prohaska <prohaska@zib.de>
2008-02-06 19:25:58 +08:00
|
|
|
int convert_to_git(const char *path, const char *src, size_t len,
|
|
|
|
struct strbuf *dst, enum safe_crlf checksafe)
|
2007-04-13 13:30:05 +08:00
|
|
|
{
|
2011-05-10 04:58:31 +08:00
|
|
|
int ret = 0;
|
|
|
|
struct conv_attrs ca;
|
2007-04-21 14:44:02 +08:00
|
|
|
|
2011-05-10 04:58:31 +08:00
|
|
|
convert_attrs(&ca, path);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN);
|
|
|
|
if (!ret && ca.drv && ca.drv->required)
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
die("%s: clean filter '%s' failed", path, ca.drv->name);
|
|
|
|
|
2012-02-25 06:02:37 +08:00
|
|
|
if (ret && dst) {
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
2011-05-10 04:58:31 +08:00
|
|
|
ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe);
|
2012-02-25 06:02:37 +08:00
|
|
|
if (ret && dst) {
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-21 14:44:02 +08:00
|
|
|
}
|
2011-05-10 04:58:31 +08:00
|
|
|
return ret | ident_to_git(path, src, len, dst, ca.ident);
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
|
|
|
|
2014-08-26 23:23:25 +08:00
|
|
|
void convert_to_git_filter_fd(const char *path, int fd, struct strbuf *dst,
|
|
|
|
enum safe_crlf checksafe)
|
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
|
|
|
convert_attrs(&ca, path);
|
|
|
|
|
|
|
|
assert(ca.drv);
|
2016-10-17 07:20:37 +08:00
|
|
|
assert(ca.drv->clean || ca.drv->process);
|
2014-08-26 23:23:25 +08:00
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))
|
2014-08-26 23:23:25 +08:00
|
|
|
die("%s: clean filter '%s' failed", path, ca.drv->name);
|
|
|
|
|
|
|
|
crlf_to_git(path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
|
|
|
|
ident_to_git(path, dst->buf, dst->len, dst, ca.ident);
|
|
|
|
}
|
|
|
|
|
2010-07-03 03:20:49 +08:00
|
|
|
static int convert_to_working_tree_internal(const char *path, const char *src,
|
|
|
|
size_t len, struct strbuf *dst,
|
|
|
|
int normalizing)
|
2007-04-13 13:30:05 +08:00
|
|
|
{
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
int ret = 0, ret_filter = 0;
|
2011-05-10 04:58:31 +08:00
|
|
|
struct conv_attrs ca;
|
2007-04-21 14:44:02 +08:00
|
|
|
|
2011-05-10 04:58:31 +08:00
|
|
|
convert_attrs(&ca, path);
|
2007-04-22 10:09:02 +08:00
|
|
|
|
2011-05-10 04:58:31 +08:00
|
|
|
ret |= ident_to_worktree(path, src, len, dst, ca.ident);
|
Rewrite convert_to_{git,working_tree} to use strbuf's.
* Now, those functions take an "out" strbuf argument, where they store their
result if any. In that case, it also returns 1, else it returns 0.
* those functions support "in place" editing, in the sense that it's OK to
call them this way:
convert_to_git(path, sb->buf, sb->len, sb);
When doable, conversions are done in place for real, else the strbuf
content is just replaced with the new one, transparentely for the caller.
If you want to create a new filter working this way, being the accumulation
of filter1, filter2, ... filtern, then your meta_filter would be:
int meta_filter(..., const char *src, size_t len, struct strbuf *sb)
{
int ret = 0;
ret |= filter1(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
ret |= filter2(...., src, len, sb);
if (ret) {
src = sb->buf;
len = sb->len;
}
....
return ret | filtern(..., src, len, sb);
}
That's why subfilters the convert_to_* functions called were also rewritten
to work this way.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-16 21:51:04 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
2007-04-22 10:09:02 +08:00
|
|
|
}
|
2010-07-03 03:20:49 +08:00
|
|
|
/*
|
|
|
|
* CRLF conversion can be skipped if normalizing, unless there
|
2016-10-17 07:20:37 +08:00
|
|
|
* is a smudge or process filter (even if the process filter doesn't
|
|
|
|
* support smudge). The filters might expect CRLFs.
|
2010-07-03 03:20:49 +08:00
|
|
|
*/
|
2016-10-17 07:20:37 +08:00
|
|
|
if ((ca.drv && (ca.drv->smudge || ca.drv->process)) || !normalizing) {
|
2011-05-10 04:58:31 +08:00
|
|
|
ret |= crlf_to_worktree(path, src, len, dst, ca.crlf_action);
|
2010-07-03 03:20:49 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2007-04-21 18:14:13 +08:00
|
|
|
}
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
|
2016-10-17 07:20:36 +08:00
|
|
|
ret_filter = apply_filter(path, src, len, -1, dst, ca.drv, CAP_SMUDGE);
|
|
|
|
if (!ret_filter && ca.drv && ca.drv->required)
|
Add a setting to require a filter to be successful
By default, a missing filter driver or a failure from the filter driver is
not an error, but merely makes the filter operation a no-op pass through.
This is useful to massage the content into a shape that is more convenient
for the platform, filesystem, and the user to use, and the content filter
mechanism is not used to turn something unusable into usable.
However, we could also use of the content filtering mechanism and store
the content that cannot be directly used in the repository (e.g. a UUID
that refers to the true content stored outside git, or an encrypted
content) and turn it into a usable form upon checkout (e.g. download the
external content, or decrypt the encrypted content). For such a use case,
the content cannot be used when filter driver fails, and we need a way to
tell Git to abort the whole operation for such a failing or missing filter
driver.
Add a new "filter.<driver>.required" configuration variable to mark the
second use case. When it is set, git will abort the operation when the
filter driver does not exist or exits with a non-zero status code.
Signed-off-by: Jehan Bing <jehan@orb.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-02-17 09:19:03 +08:00
|
|
|
die("%s: smudge filter %s failed", path, ca.drv->name);
|
|
|
|
|
|
|
|
return ret | ret_filter;
|
2007-04-13 13:30:05 +08:00
|
|
|
}
|
2010-07-03 03:20:47 +08:00
|
|
|
|
2010-07-03 03:20:49 +08:00
|
|
|
int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
|
|
|
|
{
|
|
|
|
return convert_to_working_tree_internal(path, src, len, dst, 0);
|
|
|
|
}
|
|
|
|
|
2010-07-03 03:20:47 +08:00
|
|
|
int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst)
|
|
|
|
{
|
2010-07-03 03:20:49 +08:00
|
|
|
int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
|
2010-07-03 03:20:47 +08:00
|
|
|
if (ret) {
|
|
|
|
src = dst->buf;
|
|
|
|
len = dst->len;
|
|
|
|
}
|
2016-06-28 16:01:13 +08:00
|
|
|
return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_RENORMALIZE);
|
2010-07-03 03:20:47 +08:00
|
|
|
}
|
2011-05-13 05:31:08 +08:00
|
|
|
|
2011-05-21 05:33:31 +08:00
|
|
|
/*****************************************************************
|
|
|
|
*
|
2013-07-23 05:02:23 +08:00
|
|
|
* Streaming conversion support
|
2011-05-21 05:33:31 +08:00
|
|
|
*
|
|
|
|
*****************************************************************/
|
|
|
|
|
|
|
|
typedef int (*filter_fn)(struct stream_filter *,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p);
|
|
|
|
typedef void (*free_fn)(struct stream_filter *);
|
|
|
|
|
|
|
|
struct stream_filter_vtbl {
|
|
|
|
filter_fn filter;
|
|
|
|
free_fn free;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct stream_filter {
|
|
|
|
struct stream_filter_vtbl *vtbl;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int null_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
2011-05-22 05:05:51 +08:00
|
|
|
size_t count;
|
|
|
|
|
|
|
|
if (!input)
|
|
|
|
return 0; /* we do not keep any states */
|
|
|
|
count = *isize_p;
|
2011-05-21 05:33:31 +08:00
|
|
|
if (*osize_p < count)
|
|
|
|
count = *osize_p;
|
|
|
|
if (count) {
|
|
|
|
memmove(output, input, count);
|
|
|
|
*isize_p -= count;
|
|
|
|
*osize_p -= count;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void null_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
; /* nothing -- null instances are shared */
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl null_vtbl = {
|
|
|
|
null_filter_fn,
|
|
|
|
null_free_fn,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter null_filter_singleton = {
|
|
|
|
&null_vtbl,
|
|
|
|
};
|
|
|
|
|
|
|
|
int is_null_stream_filter(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
return filter == &null_filter_singleton;
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:28:00 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* LF-to-CRLF filter
|
|
|
|
*/
|
2011-11-28 18:48:12 +08:00
|
|
|
|
|
|
|
struct lf_to_crlf_filter {
|
|
|
|
struct stream_filter filter;
|
2011-12-17 07:44:18 +08:00
|
|
|
unsigned has_held:1;
|
|
|
|
char held;
|
2011-11-28 18:48:12 +08:00
|
|
|
};
|
|
|
|
|
2011-05-21 07:47:56 +08:00
|
|
|
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
2011-11-28 18:48:12 +08:00
|
|
|
size_t count, o = 0;
|
|
|
|
struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
|
|
|
|
|
2011-12-17 07:44:18 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
2011-11-28 18:48:12 +08:00
|
|
|
}
|
2011-05-21 07:47:56 +08:00
|
|
|
|
2011-12-17 06:39:37 +08:00
|
|
|
/* We are told to drain */
|
|
|
|
if (!input) {
|
|
|
|
*osize_p -= o;
|
|
|
|
return 0;
|
|
|
|
}
|
2011-05-21 07:47:56 +08:00
|
|
|
|
|
|
|
count = *isize_p;
|
2011-12-17 07:44:18 +08:00
|
|
|
if (count || lf_to_crlf->has_held) {
|
2011-11-28 18:48:12 +08:00
|
|
|
size_t i;
|
2011-12-17 07:44:18 +08:00
|
|
|
int was_cr = 0;
|
|
|
|
|
|
|
|
if (lf_to_crlf->has_held) {
|
|
|
|
was_cr = 1;
|
|
|
|
lf_to_crlf->has_held = 0;
|
|
|
|
}
|
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
for (i = 0; o < *osize_p && i < count; i++) {
|
2011-05-21 07:47:56 +08:00
|
|
|
char ch = input[i];
|
2011-12-17 07:44:18 +08:00
|
|
|
|
2011-05-21 07:47:56 +08:00
|
|
|
if (ch == '\n') {
|
2011-11-28 18:48:12 +08:00
|
|
|
output[o++] = '\r';
|
2011-12-17 07:44:18 +08:00
|
|
|
} 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';
|
2011-05-21 07:47:56 +08:00
|
|
|
}
|
2011-12-17 07:44:18 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2011-05-21 07:47:56 +08:00
|
|
|
output[o++] = ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
*osize_p -= o;
|
|
|
|
*isize_p -= i;
|
2011-12-17 07:44:18 +08:00
|
|
|
|
|
|
|
if (!lf_to_crlf->has_held && was_cr) {
|
|
|
|
lf_to_crlf->has_held = 1;
|
|
|
|
lf_to_crlf->held = '\r';
|
|
|
|
}
|
2011-05-21 07:47:56 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
static void lf_to_crlf_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
2011-05-21 07:47:56 +08:00
|
|
|
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
|
|
|
|
lf_to_crlf_filter_fn,
|
2011-11-28 18:48:12 +08:00
|
|
|
lf_to_crlf_free_fn,
|
2011-05-21 07:47:56 +08:00
|
|
|
};
|
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
static struct stream_filter *lf_to_crlf_filter(void)
|
|
|
|
{
|
2011-12-17 06:39:37 +08:00
|
|
|
struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf));
|
2011-05-21 07:47:56 +08:00
|
|
|
|
2011-11-28 18:48:12 +08:00
|
|
|
lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
|
|
|
|
return (struct stream_filter *)lf_to_crlf;
|
|
|
|
}
|
2011-05-21 09:28:00 +08:00
|
|
|
|
2011-05-22 09:28:41 +08:00
|
|
|
/*
|
|
|
|
* Cascade filter
|
|
|
|
*/
|
|
|
|
#define FILTER_BUFFER 1024
|
|
|
|
struct cascade_filter {
|
|
|
|
struct stream_filter filter;
|
|
|
|
struct stream_filter *one;
|
|
|
|
struct stream_filter *two;
|
|
|
|
char buf[FILTER_BUFFER];
|
|
|
|
int end, ptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int cascade_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cas = (struct cascade_filter *) filter;
|
|
|
|
size_t filled = 0;
|
|
|
|
size_t sz = *osize_p;
|
|
|
|
size_t to_feed, remaining;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* input -- (one) --> buf -- (two) --> output
|
|
|
|
*/
|
|
|
|
while (filled < sz) {
|
|
|
|
remaining = sz - filled;
|
|
|
|
|
|
|
|
/* do we already have something to feed two with? */
|
|
|
|
if (cas->ptr < cas->end) {
|
|
|
|
to_feed = cas->end - cas->ptr;
|
|
|
|
if (stream_filter(cas->two,
|
|
|
|
cas->buf + cas->ptr, &to_feed,
|
|
|
|
output + filled, &remaining))
|
|
|
|
return -1;
|
|
|
|
cas->ptr += (cas->end - cas->ptr) - to_feed;
|
|
|
|
filled = sz - remaining;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* feed one from upstream and have it emit into our buffer */
|
|
|
|
to_feed = input ? *isize_p : 0;
|
|
|
|
if (input && !to_feed)
|
|
|
|
break;
|
|
|
|
remaining = sizeof(cas->buf);
|
|
|
|
if (stream_filter(cas->one,
|
|
|
|
input, &to_feed,
|
|
|
|
cas->buf, &remaining))
|
|
|
|
return -1;
|
|
|
|
cas->end = sizeof(cas->buf) - remaining;
|
|
|
|
cas->ptr = 0;
|
|
|
|
if (input) {
|
|
|
|
size_t fed = *isize_p - to_feed;
|
|
|
|
*isize_p -= fed;
|
|
|
|
input += fed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do we know that we drained one completely? */
|
|
|
|
if (input || cas->end)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* tell two to drain; we have nothing more to give it */
|
|
|
|
to_feed = 0;
|
|
|
|
remaining = sz - filled;
|
|
|
|
if (stream_filter(cas->two,
|
|
|
|
NULL, &to_feed,
|
|
|
|
output + filled, &remaining))
|
|
|
|
return -1;
|
|
|
|
if (remaining == (sz - filled))
|
|
|
|
break; /* completely drained two */
|
|
|
|
filled = sz - remaining;
|
|
|
|
}
|
|
|
|
*osize_p -= filled;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cascade_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cas = (struct cascade_filter *)filter;
|
|
|
|
free_stream_filter(cas->one);
|
|
|
|
free_stream_filter(cas->two);
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl cascade_vtbl = {
|
|
|
|
cascade_filter_fn,
|
|
|
|
cascade_free_fn,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter *cascade_filter(struct stream_filter *one,
|
|
|
|
struct stream_filter *two)
|
|
|
|
{
|
|
|
|
struct cascade_filter *cascade;
|
|
|
|
|
|
|
|
if (!one || is_null_stream_filter(one))
|
|
|
|
return two;
|
|
|
|
if (!two || is_null_stream_filter(two))
|
|
|
|
return one;
|
|
|
|
|
|
|
|
cascade = xmalloc(sizeof(*cascade));
|
|
|
|
cascade->one = one;
|
|
|
|
cascade->two = two;
|
|
|
|
cascade->end = cascade->ptr = 0;
|
|
|
|
cascade->filter.vtbl = &cascade_vtbl;
|
|
|
|
return (struct stream_filter *)cascade;
|
|
|
|
}
|
|
|
|
|
2011-05-21 09:28:00 +08:00
|
|
|
/*
|
|
|
|
* ident filter
|
|
|
|
*/
|
|
|
|
#define IDENT_DRAINING (-1)
|
|
|
|
#define IDENT_SKIPPING (-2)
|
|
|
|
struct ident_filter {
|
|
|
|
struct stream_filter filter;
|
|
|
|
struct strbuf left;
|
|
|
|
int state;
|
|
|
|
char ident[45]; /* ": x40 $" */
|
|
|
|
};
|
|
|
|
|
|
|
|
static int is_foreign_ident(const char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-19 03:47:50 +08:00
|
|
|
if (!skip_prefix(str, "$Id: ", &str))
|
2011-05-21 09:28:00 +08:00
|
|
|
return 0;
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-19 03:47:50 +08:00
|
|
|
for (i = 0; str[i]; i++) {
|
2011-05-21 09:28:00 +08:00
|
|
|
if (isspace(str[i]) && str[i+1] != '$')
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ident_drain(struct ident_filter *ident, char **output_p, size_t *osize_p)
|
|
|
|
{
|
|
|
|
size_t to_drain = ident->left.len;
|
|
|
|
|
|
|
|
if (*osize_p < to_drain)
|
|
|
|
to_drain = *osize_p;
|
|
|
|
if (to_drain) {
|
|
|
|
memcpy(*output_p, ident->left.buf, to_drain);
|
|
|
|
strbuf_remove(&ident->left, 0, to_drain);
|
|
|
|
*output_p += to_drain;
|
|
|
|
*osize_p -= to_drain;
|
|
|
|
}
|
|
|
|
if (!ident->left.len)
|
|
|
|
ident->state = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ident_filter_fn(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = (struct ident_filter *)filter;
|
|
|
|
static const char head[] = "$Id";
|
|
|
|
|
|
|
|
if (!input) {
|
|
|
|
/* drain upon eof */
|
|
|
|
switch (ident->state) {
|
|
|
|
default:
|
|
|
|
strbuf_add(&ident->left, head, ident->state);
|
|
|
|
case IDENT_SKIPPING:
|
|
|
|
/* fallthru */
|
|
|
|
case IDENT_DRAINING:
|
|
|
|
ident_drain(ident, &output, osize_p);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*isize_p || (ident->state == IDENT_DRAINING)) {
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
if (ident->state == IDENT_DRAINING) {
|
|
|
|
ident_drain(ident, &output, osize_p);
|
|
|
|
if (!*osize_p)
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch = *(input++);
|
|
|
|
(*isize_p)--;
|
|
|
|
|
|
|
|
if (ident->state == IDENT_SKIPPING) {
|
|
|
|
/*
|
|
|
|
* Skipping until '$' or LF, but keeping them
|
|
|
|
* in case it is a foreign ident.
|
|
|
|
*/
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
if (ch != '\n' && ch != '$')
|
|
|
|
continue;
|
|
|
|
if (ch == '$' && !is_foreign_ident(ident->left.buf)) {
|
|
|
|
strbuf_setlen(&ident->left, sizeof(head) - 1);
|
|
|
|
strbuf_addstr(&ident->left, ident->ident);
|
|
|
|
}
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ident->state < sizeof(head) &&
|
|
|
|
head[ident->state] == ch) {
|
|
|
|
ident->state++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ident->state)
|
|
|
|
strbuf_add(&ident->left, head, ident->state);
|
|
|
|
if (ident->state == sizeof(head) - 1) {
|
|
|
|
if (ch != ':' && ch != '$') {
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ch == ':') {
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = IDENT_SKIPPING;
|
|
|
|
} else {
|
|
|
|
strbuf_addstr(&ident->left, ident->ident);
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
strbuf_addch(&ident->left, ch);
|
|
|
|
ident->state = IDENT_DRAINING;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ident_free_fn(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = (struct ident_filter *)filter;
|
|
|
|
strbuf_release(&ident->left);
|
|
|
|
free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stream_filter_vtbl ident_vtbl = {
|
|
|
|
ident_filter_fn,
|
|
|
|
ident_free_fn,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct stream_filter *ident_filter(const unsigned char *sha1)
|
|
|
|
{
|
|
|
|
struct ident_filter *ident = xmalloc(sizeof(*ident));
|
|
|
|
|
2015-09-25 05:06:08 +08:00
|
|
|
xsnprintf(ident->ident, sizeof(ident->ident),
|
|
|
|
": %s $", sha1_to_hex(sha1));
|
2011-05-21 09:28:00 +08:00
|
|
|
strbuf_init(&ident->left, 0);
|
|
|
|
ident->filter.vtbl = &ident_vtbl;
|
|
|
|
ident->state = 0;
|
|
|
|
return (struct stream_filter *)ident;
|
|
|
|
}
|
|
|
|
|
2011-05-13 05:31:08 +08:00
|
|
|
/*
|
2011-05-21 05:33:31 +08:00
|
|
|
* Return an appropriately constructed filter for the path, or NULL if
|
|
|
|
* the contents cannot be filtered without reading the whole thing
|
|
|
|
* in-core.
|
|
|
|
*
|
|
|
|
* Note that you would be crazy to set CRLF, smuge/clean or ident to a
|
|
|
|
* large binary blob you would want us not to slurp into the memory!
|
2011-05-13 05:31:08 +08:00
|
|
|
*/
|
2011-05-21 05:33:31 +08:00
|
|
|
struct stream_filter *get_stream_filter(const char *path, const unsigned char *sha1)
|
2011-05-13 05:31:08 +08:00
|
|
|
{
|
|
|
|
struct conv_attrs ca;
|
2011-05-21 09:28:00 +08:00
|
|
|
struct stream_filter *filter = NULL;
|
2011-05-13 05:31:08 +08:00
|
|
|
|
|
|
|
convert_attrs(&ca, path);
|
2016-10-17 07:20:37 +08:00
|
|
|
if (ca.drv && (ca.drv->process || ca.drv->smudge || ca.drv->clean))
|
2016-04-26 00:56:32 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (ca.crlf_action == CRLF_AUTO || ca.crlf_action == CRLF_AUTO_CRLF)
|
|
|
|
return NULL;
|
2011-05-21 09:28:00 +08:00
|
|
|
|
|
|
|
if (ca.ident)
|
|
|
|
filter = ident_filter(sha1);
|
2011-05-13 05:31:08 +08:00
|
|
|
|
2016-04-26 00:56:32 +08:00
|
|
|
if (output_eol(ca.crlf_action) == EOL_CRLF)
|
2011-11-28 18:48:12 +08:00
|
|
|
filter = cascade_filter(filter, lf_to_crlf_filter());
|
2016-04-26 00:56:32 +08:00
|
|
|
else
|
|
|
|
filter = cascade_filter(filter, &null_filter_singleton);
|
2011-05-21 07:47:56 +08:00
|
|
|
|
2011-05-21 09:28:00 +08:00
|
|
|
return filter;
|
2011-05-21 05:33:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void free_stream_filter(struct stream_filter *filter)
|
|
|
|
{
|
|
|
|
filter->vtbl->free(filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
int stream_filter(struct stream_filter *filter,
|
|
|
|
const char *input, size_t *isize_p,
|
|
|
|
char *output, size_t *osize_p)
|
|
|
|
{
|
|
|
|
return filter->vtbl->filter(filter, input, isize_p, output, osize_p);
|
2011-05-13 05:31:08 +08:00
|
|
|
}
|