strbuf: make strbuf_getline_crlf() global

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 <gitster@pobox.com>

Junio C Hamano committed Oct 28, 2015 at 13:17 UTC c8aa9fdf5dc15e2c508acb22df03d431983569ed
3 files changed +19 -15
builtin/am.c
-15
@@ -45,21 +45,6 @@ static int is_empty_file(const char *filename)
45 return !st.st_size;
46 }
47
48 -/**
49 - * Like strbuf_getline(), but treats both '\n' and "\r\n" as line terminators.
50 - */
51 -static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
52 -{
53 - if (strbuf_getwholeline(sb, fp, '\n'))
54 - return EOF;
55 - if (sb->buf[sb->len - 1] == '\n') {
56 - strbuf_setlen(sb, sb->len - 1);
57 - if (sb->len > 0 && sb->buf[sb->len - 1] == '\r')
58 - strbuf_setlen(sb, sb->len - 1);
59 - }
60 - return 0;
61 -}
62 -
48 /**
49 * Returns the length of the first line of msg.
50 */
strbuf.c
+12
@@ -510,6 +510,18 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
510 return 0;
511 }
512
513 +int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)
514 +{
515 + if (strbuf_getwholeline(sb, fp, '\n'))
516 + return EOF;
517 + if (sb->buf[sb->len - 1] == '\n') {
518 + strbuf_setlen(sb, sb->len - 1);
519 + if (sb->len && sb->buf[sb->len - 1] == '\r')
520 + strbuf_setlen(sb, sb->len - 1);
521 + }
522 + return 0;
523 +}
524 +
525 int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
526 {
527 strbuf_reset(sb);
strbuf.h
+7
@@ -388,6 +388,13 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
388 */
389 extern int strbuf_getline(struct strbuf *, FILE *, int);
390
391 +/*
392 + * Similar to strbuf_getline(), but uses '\n' as the terminator,
393 + * and additionally treats a '\r' that comes immediately before '\n'
394 + * as part of the terminator.
395 + */
396 +extern int strbuf_getline_crlf(struct strbuf *, FILE *);
397 +
398 /**
399 * Like `strbuf_getline`, but keeps the trailing terminator (if
400 * any) in the buffer.