Skip to content

Commit

Permalink
strbuf: make strbuf_getline_crlf() global
Browse files Browse the repository at this point in the history
Often we read "text" files that are supplied by the end user
(e.g. commit log message that was edited with $GIT_EDITOR upon 'git
commit -e'), and in some environments lines in a text file are
terminated with CRLF.  Existing strbuf_getline() knows to read a
single line and then strip the terminating byte from the result, but
it is handy to have a version that is more tailored for a "text"
input that takes both '\n' and '\r\n' as line terminator (aka
<newline> in POSIX lingo) and returns the body of the line after
stripping <newline>.

Recently reimplemented "git am" uses such a function implemented
privately; move it to strbuf.[ch] and make it available for others.

Note that we do not blindly replace calls to strbuf_getline() that
uses LF as the line terminator with calls to strbuf_getline_crlf()
and this is very much deliberate.  Some callers may want to treat an
incoming line that ends with CR (and terminated with LF) to have a
payload that includes the final CR, and such a blind replacement
will result in misconversion when done without code audit.

Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
gitster committed Jan 14, 2016
1 parent dce80bd commit c8aa9fd
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 15 deletions.
15 changes: 0 additions & 15 deletions builtin/am.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,6 @@ static int is_empty_file(const char *filename)
return !st.st_size;
}

/**
* Like strbuf_getline(), but treats both '\n' and "\r\n" as line terminators.
*/
static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
{
if (strbuf_getwholeline(sb, fp, '\n'))
return EOF;
if (sb->buf[sb->len - 1] == '\n') {
strbuf_setlen(sb, sb->len - 1);
if (sb->len > 0 && sb->buf[sb->len - 1] == '\r')
strbuf_setlen(sb, sb->len - 1);
}
return 0;
}

/**
* Returns the length of the first line of msg.
*/
Expand Down
12 changes: 12 additions & 0 deletions strbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,18 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
return 0;
}

int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
{
if (strbuf_getwholeline(sb, fp, '\n'))
return EOF;
if (sb->buf[sb->len - 1] == '\n') {
strbuf_setlen(sb, sb->len - 1);
if (sb->len && sb->buf[sb->len - 1] == '\r')
strbuf_setlen(sb, sb->len - 1);
}
return 0;
}

int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
{
strbuf_reset(sb);
Expand Down
7 changes: 7 additions & 0 deletions strbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,13 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
*/
extern int strbuf_getline(struct strbuf *, FILE *, int);

/*
* Similar to strbuf_getline(), but uses '\n' as the terminator,
* and additionally treats a '\r' that comes immediately before '\n'
* as part of the terminator.
*/
extern int strbuf_getline_crlf(struct strbuf *, FILE *);

/**
* Like `strbuf_getline`, but keeps the trailing terminator (if
* any) in the buffer.
Expand Down

0 comments on commit c8aa9fd

Please sign in to comment.