{"thread":{"id":"40059","subject":"[PATCH] revisions --stdin: accept CRLF line terminators","startedAt":"2015-08-11T20:21:33Z","lastAt":"2016-01-15T23:31:02Z","messageCount":114,"participants":["Johannes Sixt","Junio C Hamano","Johannes Schindelin","Jeff King","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"267858","messageId":"55CA594D.5020103@kdbg.org","threadId":"40059","inReplyTo":null,"subject":"[PATCH] revisions --stdin: accept CRLF line terminators","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-08-11T20:21:33Z","receivedAt":"2015-08-11T20:21:33Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"On Windows, 'git rebase -i' with rebase.missingCommitsCheck set to\nwarn or error reports:\n\n   Dropped commits (newer to older):\n   'atal: bad revision '410dee56...\n\nThe error comes from the git rev-list --stdin invocation in\ngit-rebase--interactive.sh (function check_todo_list). It is caused by\nCRs that end up in the file \"$todo\".miss, because many tools of the MSYS\ntoolset force LF to CRLF conversion when regular files are written via\nstdout.\n\nTo fix the error, permit CRLF line terminators when revisions and\npathspec are read using the --stdin option.\n\nSigned-off-by: Johannes Sixt <j6t@kdbg.org>\n---\n This fixes a new failure in the test suite (t3404.8[67]) on Windows, but\n I got around to debug it only now.\n\n revision.c                |  4 ++++\n t/t6017-rev-list-stdin.sh | 16 ++++++++++++++++\n 2 files changed, 20 insertions(+)\n\ndiff --git a/revision.c b/revision.c\nindex cf60c5d..4efedeb 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1641,6 +1641,8 @@ static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n \t\tint len = sb->len;\n \t\tif (len && sb->buf[len - 1] == '\\n')\n \t\t\tsb->buf[--len] = '\\0';\n+\t\tif (len && sb->buf[len - 1] == '\\r')\n+\t\t\tsb->buf[--len] = '\\0';\n \t\tALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n \t\tprune->path[prune->nr++] = xstrdup(sb->buf);\n \t}\n@@ -1661,6 +1663,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \t\tint len = sb.len;\n \t\tif (len && sb.buf[len - 1] == '\\n')\n \t\t\tsb.buf[--len] = '\\0';\n+\t\tif (len && sb.buf[len - 1] == '\\r')\n+\t\t\tsb.buf[--len] = '\\0';\n \t\tif (!len)\n \t\t\tbreak;\n \t\tif (sb.buf[0] == '-') {\ndiff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh\nindex 667b375..34c43cf 100755\n--- a/t/t6017-rev-list-stdin.sh\n+++ b/t/t6017-rev-list-stdin.sh\n@@ -75,4 +75,20 @@ test_expect_success 'not only --stdin' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'accept CRLF line terminators' '\n+\tcat >expect <<-\\EOF &&\n+\t7\n+\n+\tfile-2\n+\tEOF\n+\tq_to_cr >input <<-\\EOF &&\n+\tmasterQ\n+\t^master^Q\n+\t--Q\n+\tfile-2Q\n+\tEOF\n+\tgit log --pretty=tformat:%s --name-only --stdin <input >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.3.2.245.gb5bf9d3\n\n-- \n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n*** Please avoid top-posting. ***\nThe msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, and view previous threads, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n\n--- \nYou received this message because you are subscribed to the Google Groups \"Git for Windows\" group.\nTo unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.\nFor more options, visit https://groups.google.com/d/optout.\n"},{"id":"267869","messageId":"xmqqr3n9pkzc.fsf@gitster.dls.corp.google.com","threadId":"40059","inReplyTo":"55CA594D.5020103@kdbg.org","subject":"Re: [PATCH] revisions --stdin: accept CRLF line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-11T21:35:03Z","receivedAt":"2015-08-11T21:35:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> On Windows, 'git rebase -i' with rebase.missingCommitsCheck set to\n> warn or error reports:\n>\n>    Dropped commits (newer to older):\n>    'atal: bad revision '410dee56...\n>\n> The error comes from the git rev-list --stdin invocation in\n> git-rebase--interactive.sh (function check_todo_list). It is caused by\n> CRs that end up in the file \"$todo\".miss, because many tools of the MSYS\n> toolset force LF to CRLF conversion when regular files are written via\n> stdout.\n>\n> To fix the error, permit CRLF line terminators when revisions and\n> pathspec are read using the --stdin option.\n>\n> Signed-off-by: Johannes Sixt <j6t@kdbg.org>\n> ---\n>  This fixes a new failure in the test suite (t3404.8[67]) on Windows, but\n>  I got around to debug it only now.\n>\n>  revision.c                |  4 ++++\n>  t/t6017-rev-list-stdin.sh | 16 ++++++++++++++++\n>  2 files changed, 20 insertions(+)\n>\n> diff --git a/revision.c b/revision.c\n> index cf60c5d..4efedeb 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -1641,6 +1641,8 @@ static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n>  \t\tint len = sb->len;\n>  \t\tif (len && sb->buf[len - 1] == '\\n')\n>  \t\t\tsb->buf[--len] = '\\0';\n> +\t\tif (len && sb->buf[len - 1] == '\\r')\n> +\t\t\tsb->buf[--len] = '\\0';\n>  \t\tALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n>  \t\tprune->path[prune->nr++] = xstrdup(sb->buf);\n>  \t}\n> @@ -1661,6 +1663,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n>  \t\tint len = sb.len;\n>  \t\tif (len && sb.buf[len - 1] == '\\n')\n>  \t\t\tsb.buf[--len] = '\\0';\n> +\t\tif (len && sb.buf[len - 1] == '\\r')\n> +\t\t\tsb.buf[--len] = '\\0';\n\nThis will strip lone CR at the end of line, in addition to CRLF at\nthe end of line (which you want to handle) and LF at the end of line\n(we always have removed), making it work even on ancient MacOS.\n\nIf we really cared, I guess we could write it like this:\n\n\tif (len && sb.buf[len - 1] == '\\n') {\n        \tlen--;\n                if (len && sb.buf[len - 1] == '\\r')\n                \tlen--;\n\t\tsb.buf[len] = '\\0';\n\t}\n\nbut your version should be fine as-is.\n\nThanks.\n\n> diff --git a/t/t6017-rev-list-stdin.sh b/t/t6017-rev-list-stdin.sh\n> index 667b375..34c43cf 100755\n> --- a/t/t6017-rev-list-stdin.sh\n> +++ b/t/t6017-rev-list-stdin.sh\n> @@ -75,4 +75,20 @@ test_expect_success 'not only --stdin' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> +test_expect_success 'accept CRLF line terminators' '\n> +\tcat >expect <<-\\EOF &&\n> +\t7\n> +\n> +\tfile-2\n> +\tEOF\n> +\tq_to_cr >input <<-\\EOF &&\n> +\tmasterQ\n> +\t^master^Q\n> +\t--Q\n> +\tfile-2Q\n> +\tEOF\n> +\tgit log --pretty=tformat:%s --name-only --stdin <input >actual &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>  test_done\n> -- \n> 2.3.2.245.gb5bf9d3\n>\n> -- \n\n-- \n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n*** Please avoid top-posting. ***\nThe msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, and view previous threads, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n\n--- \nYou received this message because you are subscribed to the Google Groups \"Git for Windows\" group.\nTo unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.\nFor more options, visit https://groups.google.com/d/optout.\n"},{"id":"267873","messageId":"xmqqtws5o4lp.fsf@gitster.dls.corp.google.com","threadId":"40059","inReplyTo":"xmqqr3n9pkzc.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] revisions --stdin: accept CRLF line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-08-11T22:14:10Z","receivedAt":"2015-08-11T22:14:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Johannes Sixt <j6t@kdbg.org> writes:\n>\n>> On Windows, 'git rebase -i' with rebase.missingCommitsCheck set to\n>> warn or error reports:\n>>\n>>    Dropped commits (newer to older):\n>>    'atal: bad revision '410dee56...\n>>\n>> The error comes from the git rev-list --stdin invocation in\n>> git-rebase--interactive.sh (function check_todo_list)....\n\nWe have other places that take long list of things via --stdin\noption.  It somehow feels incomplete to patch only rev-list and not\nothers, doesn't it?\n\nI looked at hits from 'grep -e --stdin Documentation/'.  Here are\nthe findings.\n\n1. These use strbuf_getline() to get one line at a time into a\n   strbuf and expects the line termination stripped off (i.e. these\n   callers do not want to worry about having LF at the end):\n\n        check-attr --stdin\n        check-ingore --stdin\n        check-mailmap --stdin\n        checkout-index --stdin\n        hash-object --stdin-paths\n        http-fetch --stdin\n        notes --stdin\n        send-pack --stdin\n        update-index --index-info\n\n2. Any command in the \"log\" family uses strbuf_getwholeline(), so it\n   needs to know about the LF at the end explicitly:\n\n        rev-list --stdin\n        show --stdin\n        cherry-pick --stdin\n        ...\n\n3. This uses fgets() into a fixed buffer; it calls get_sha1_hex() on\n   it, and the expected input is one 40-hex per line, so it does not\n   matter if there is an extra CR at the end immediately before LF.\n\n        diff-tree --stdin\n\n4. This slurps everything in-core, instead of going line-by-line.\n\n        update-ref --stdin\n\nNow, I am wondering if it makes sense to do these two things:\n\n * Teach revision.c::read_revisions_from_stdin() to use\n   strbuf_getline() instead of strbuf_getwholeline().\n\n * Teach strbuf_getline() to remove CR at the end when stripping the\n   LF at the end, only if \"term\" parameter is set to LF.\n\nDoing so would solve 1. and 2., but we obviously need to audit all\nthe other uses of strbuf_getline() to see if they can benefit (or if\nsome of them may be broken because they _always_ need LF terminated\nlines, i.e. CRLF terminated input is illegal to them).\n\nAs to 3., I think it is OK.  The code structure of 4. is too ugly\nand needs to be revamped to go one line at a time first before even\nthinking about how to proceed, I would think.\n\nThoughts?\n\n-- \n-- \n*** Please reply-to-all at all times ***\n*** (do not pretend to know who is subscribed and who is not) ***\n*** Please avoid top-posting. ***\nThe msysGit Wiki is here: https://github.com/msysgit/msysgit/wiki - Github accounts are free.\n\nYou received this message because you are subscribed to the Google\nGroups \"msysGit\" group.\nTo post to this group, send email to msysgit@googlegroups.com\nTo unsubscribe from this group, send email to\nmsysgit+unsubscribe@googlegroups.com\nFor more options, and view previous threads, visit this group at\nhttp://groups.google.com/group/msysgit?hl=en_US?hl=en\n\n--- \nYou received this message because you are subscribed to the Google Groups \"Git for Windows\" group.\nTo unsubscribe from this group and stop receiving emails from it, send an email to msysgit+unsubscribe@googlegroups.com.\nFor more options, visit https://groups.google.com/d/optout.\n"},{"id":"267928","messageId":"55CB8F71.1020402@kdbg.org","threadId":"40059","inReplyTo":"xmqqtws5o4lp.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] revisions --stdin: accept CRLF line terminators","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-08-12T18:24:49Z","receivedAt":"2015-08-12T18:24:49Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 12.08.2015 um 00:14 schrieb Junio C Hamano:\n> Now, I am wondering if it makes sense to do these two things:\n>\n>   * Teach revision.c::read_revisions_from_stdin() to use\n>     strbuf_getline() instead of strbuf_getwholeline().\n>\n>   * Teach strbuf_getline() to remove CR at the end when stripping the\n>     LF at the end, only if \"term\" parameter is set to LF.\n>\n> Doing so would solve 1. and 2., but we obviously need to audit all\n> the other uses of strbuf_getline() to see if they can benefit (or if\n> some of them may be broken because they _always_ need LF terminated\n> lines, i.e. CRLF terminated input is illegal to them).\n\nI can see what I can do with these. Don't hold your breath, though.\n\n> As to 3., I think it is OK.  The code structure of 4. is too ugly\n> and needs to be revamped to go one line at a time first before even\n> thinking about how to proceed, I would think.\n\nRegarding update-ref --stdin (your 4.), I notice that the input format \nis very strict, so the solution is to allow an optional CR before the \nLF. I alread have a patch, but it skips all trailing space, which is \nprobably too lenient. (I only needed the patch once for a debug \nsesssion, but there is no obvious breakage without the patch.)\n\n-- Hannes\n"},{"id":"272442","messageId":"1446071161-15610-1-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"xmqqtws5o4lp.fsf@gitster.dls.corp.google.com","subject":"[PATCH 00/17] Peace with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:44Z","receivedAt":"2015-10-28T22:25:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We have too many topics titled \"War on something\"; let's try to make\npeace for a change.\n\nThis is a continuation to $gmane/275735, which is filed in the\narchive under another mailing list:\n\n  http://thread.gmane.org/gmane.comp.version-control.msysgit/21773\n\nWe read \"text\" files from filesystem (or from the standard input) in\nvarious places in the code.  Some of them are written by us, but\nothers are often prepared by an editor driven by human user.  Even\nthough we write (and expect) lines in these text files to be\nterminated with LF (not CRLF), the end-user's editor can be told to\nuse CRLF termination, and on some platforms that may be the default.\n\nBecause many codepaths (e.g. commit log message) first pass the\ncontents of such a file through stripspace(), and as a side effect\nof discarding the whitespace at the end of each line, lines\nterminated with CRLF are normalized to LF terminated lines (but we\ndo not lose a lone CR in the middle of a non-blank string), this is\nnot a problem in many codepaths.  But not all of the codepaths are\nsafe.\n\nTypically, we use strbuf_getline() to read these \"text\" files, which\nreads a single line up to the first LF into a buffer, discard that\nLF at the end, and returns (an incomplete last line gets returned\nas-is).  In theory, these places that expect to read \"text\", we\nshould be able to update the lotic to read a line up to the first\nLF, discard that LF, together with a CR if one appears immediately\nbefore that LF, without breaking anything.\n\nI inspected all the callsites of this function to see if it is safe\nto use such an updated logic at these callsites, and did not find\nanything problematic.  I could update strbuf_getline() in place, but\njust to be extra careful, this series instead introduces another\nhelper, strbuf_gets(), that is aware of this CRLF business, and\nconvert the ones that are safe to update as we verify.\n\nAt the end of this message, you will find my notes while inspecting\nthe current codebase as of 37023ba3 (Seventh batch for 2.7,\n2015-10-26).\n\n * This series converts only the callers of strbuf_getline() in the\n   category [A], i.e. the current code would misbehave when fed a\n   file with CRLF-terminated lines and use the data with an unwanted\n   CR appended at the end, and with the update the code should work\n   as intended with such a file, without breaking the expected\n   behaviour when working on a file with LF-terminated lines.\n\n * Callers that expect to read from our own output do not have to\n   accomodate CRLF-terminated lines, but they can be updated to do\n   so safely if we do not rely on the ability to express a payload\n   that has CR at the end.  For example, the insn sheet \"rebase -i\"\n   uses typically end with commit log summary that we ourselves do\n   not read or use, so even if the end-user on a platform with LF\n   lines deliberately does insert \\r at the end of the line and\n   strbuf_gets() removed that \\r from the payload, no unexpected\n   behaviour should happen.  They are categorized as [B] in the\n   attached notes (and this series does not touch them).\n\n * Some callers just strbuf_trim() or otherwise have logic that\n   tolerates whitespaces at the end of the line.  For them, it does\n   not make any difference whether strbuf_getline() or strbuf_gets()\n   is used to read the lines to be processed.  They are caregorized\n   as [C] in the attached notes (and this series does not touch\n   them).\n\n * I haven't found a caller that wants to only see LF-terminated\n   lines (in other words, \"ABC\\r\\n\" must be treated as a line with 4\n   bytes payload on it, A B C and CR), but the survey reserves\n   category name [X] for this empty set ;-).\n\nDouble-checking my classification for callers in [B] and [C] and\nmaking them all use strbuf_gets() would be a good microproject for\nGSoC in coming years ;-) If all callers with strbuf_getline() that\nuses '\\n' as the terminator disappears at the end, that would be\nideal.\n\nJunio C Hamano (17):\n  strbuf: add strbuf_gets()\n  check-attr, check-ignore, checkout-index: read paths with strbuf_gets()\n  update-index: read --index-info with strbuf_gets()\n  update-index: read list of paths with strbuf_gets() under --stdin\n  mktree: read textual tree representation with strbuf_gets()\n  hash-object: read --stdin-paths with strbuf_gets()\n  revision: read --stdin with strbuf_gets()\n  rev-parse: read parseopt spec with strbuf_gets()\n  ident.c: read /etc/mailname with strbuf_gets()\n  remote.c: read $GIT_DIR/remotes/* with strbuf_gets()\n  clone/sha1_file: read info/alternates with strbuf_gets()\n  transport-helper: read helper response with strbuf_gets()\n  cat-file: read batch stream with strbuf_gets()\n  column: read lines with strbuf_gets()\n  send-pack: read list of refs with strbuf_gets()\n  grep: read -f file with strbuf_gets()\n  test-sha1-array: read command stream with strbuf_gets()\n\n builtin/am.c             | 23 ++++-------------------\n builtin/cat-file.c       |  2 +-\n builtin/check-attr.c     |  4 +++-\n builtin/check-ignore.c   |  5 ++++-\n builtin/checkout-index.c |  4 +++-\n builtin/clone.c          |  2 +-\n builtin/column.c         |  2 +-\n builtin/grep.c           |  2 +-\n builtin/hash-object.c    |  2 +-\n builtin/mktree.c         |  4 +++-\n builtin/rev-parse.c      |  4 ++--\n builtin/send-pack.c      |  2 +-\n builtin/update-index.c   |  9 +++++++--\n ident.c                  |  2 +-\n remote.c                 |  2 +-\n revision.c               |  9 ++-------\n sha1_file.c              |  2 +-\n strbuf.c                 | 16 ++++++++++++++--\n strbuf.h                 |  7 +++++++\n test-sha1-array.c        |  2 +-\n transport-helper.c       |  2 +-\n 21 files changed, 60 insertions(+), 47 deletions(-)\n\n-- >8 -- survey of current strbuf_getline() callers -- >8 --\n\nupdating == \"teaching strbuf_getline() to strip CR that comes\n             immediately before the LF\"\n\n[A] may be problematic on CRLF systems, \"updating\" will help fixing.\n\n[B] CRLF line ending may or may not appear, but \"updating\" does not hurt.\n\n[C] CRLF line ending may appear, but the code is already safe.\n\n[X] The caller cares about distinction between CRLF and LF, and \"updating\"\n    introduce breakage.\n\n\nbisect.c uses it to read from BISECT_NAMES, which is a text\nfile written by redirecting \"rev-parse --sq-quote\" into it. [B]\n\nbisect.c uses it to read from BISECT_EXPECTED_REV, which is\na \"ref-like\" file written by update_ref(). [B]\n\n*** This should be cleaned up to use read_ref() or something.\n\nident.c reads from /etc/mailname, which is a text file. [A]\n*** mailnamebuf may want to be strbuf_strip()'ed, and doing so is\nanother way to fix this.\n\ncredential-cache--daemon.c uses it to read requests, which is a text\nchannel. [B]\n\ncredential-store.c uses it to read from the credential file, which is\na text file. However, it is parsed by credential_from_url() that is\nnot affected by an extra CR at the end. [C]\n\ncredential-store.c parrots the original in CRLF as CRLF with \"store\",\nwhile writing a new one with LF.  This codepath will start normalizing\nthe resulting file to LF, which may not be a bad thing. [C]\n\ncredential.c uses it to read from the helper. [B]\n\ndaemon.c uses it to read from a child process's output in order to\nsave it to the log.  The current code may have sent string with CR at\nthe end to logerror(). [A]\n\nfast-import.c uses it to read the command stream, which is text. [B]\n\nremote-curl.c uses it as a transport helper to read commadn stream,\nwhich is text [B]\n\nremote-testsvn.c uses it as a transport helper to read commadn stream,\nwhich is text [B]\n\nremote.c uses it to read $GIT_DIR/remotes/* files, which is text. [A]\n\nsequencer.c uses it to read $GIT_DIR/sequencer/head that it itself\nwrites. [B]\n\nbuiltin/clone.c and sha1_file.c uses it to read from an alternates\nfile, which is text.  [A]\n\nshell.c does end-user interactions ;-) [B]\n\ntest-sha1-array.c reads command stream, which is text [A].\n\ntransport-helper.c reads helper output, which is text [A].\n\nwalker.c reads from the standard input a <target> HT <ref> per line,\nwhich is text [A].\n\nwt-status.c reads from rebase-i insn, which is text, but it uses\nstrbuf_trim() on it [C].\n\nwt-status.c also reads from various \"ref-like\" things, all of which\nare internally generated by us [B].\n\nbuiltin/am.c does a lot to process mail input. [A]\n\nbuiltin/cat-file.c uses it to read --batch input, which is text [A].\n\nbuiltin/checkout-index.c, builtin/check-attr.c and\nbuiltin/check-ignore.c use it to read --stdin, which is text [A].\n\nbuiltin/check-mailmap.c uses it to read --stdin, but the tail end of\nthe input line is not used [C].\n\nbuiltin/clean.c does end-user interactions; it trims so it is safe [C].\n\nbuiltin/column.c reads from standard input text. [A]\n\nbuiltin/commit.c reads from MERGE_HEAD which is internally generated\n[B].\n\nbuiltin/fetch-pack.c reads list of refs with --stdin, which is\ninternally generated [B].\n\nbuiltin/grep.c uses it to read patterns from a file with -f [A].\n\nbuiltin/hash-object.c uses it with --stdin-paths [A].\n\nmailinfo uses it to read from its input [B].\n\nbuiltin/mktree.c reads etxt-formatted tree representation [A].\n\nbuiltin/notes.c reads from the standard input upon \"git notes copy\";\nthe input is trimmed [C].\n\nbuiltin/pull.c reads FETCH_HEAD which is internally generated [B].\n\nbuiltin/repack.c reads the packname output by pack-objects which is\ninternally generated [B].\n\nbuiltin/rev-parse.c uses it for its parseopt mode [A].\n\nbuiltin/send-pack.c uses it to read the refs from --stdin [A].\n\nbuiltin/update-index.c reads \"--index-info\" [A].\n\nbuiltin/update-index.c reads paths from \"--stdin\" [A].\n"},{"id":"272453","messageId":"1446071161-15610-2-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 01/17] strbuf: add strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:45Z","receivedAt":"2015-10-28T22:25:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Often we read \"text\" files that are supplied by the end user\n(e.g. commit log message that was edited with $GIT_EDITOR upon 'git\ncommit -e'), and in some environments lines in a text file are\nterminated with CRLF.  Existing strbuf_getline() knows to read a\nsingle line and then strip the terminating byte from the result, but\nit is handy to have a version that is more tailored for a \"text\"\ninput that takes both '\\n' and '\\r\\n' as line terminator (aka\n<newline> in POSIX lingo) and returns the body of the line after\nstripping <newline>.\n\nRecently reimplemented \"git am\" already uses such a function\nimplemented privately; move it to strbuf.[ch] and make it available\nfor others.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 23 ++++-------------------\n strbuf.c     | 16 ++++++++++++++--\n strbuf.h     |  7 +++++++\n 3 files changed, 25 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 4e396c8..9376d5e 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -45,21 +45,6 @@ static int is_empty_file(const char *filename)\n }\n \n /**\n- * Like strbuf_getline(), but treats both '\\n' and \"\\r\\n\" as line terminators.\n- */\n-static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n-{\n-\tif (strbuf_getwholeline(sb, fp, '\\n'))\n-\t\treturn EOF;\n-\tif (sb->buf[sb->len - 1] == '\\n') {\n-\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t\tif (sb->len > 0 && sb->buf[sb->len - 1] == '\\r')\n-\t\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n  * Returns the length of the first line of msg.\n  */\n static int linelen(const char *msg)\n@@ -627,7 +612,7 @@ static int is_mail(FILE *fp)\n \tif (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))\n \t\tdie(\"invalid pattern: %s\", header_regex);\n \n-\twhile (!strbuf_getline_crlf(&sb, fp)) {\n+\twhile (!strbuf_gets(&sb, fp)) {\n \t\tif (!sb.len)\n \t\t\tbreak; /* End of header */\n \n@@ -674,7 +659,7 @@ static int detect_patch_format(const char **paths)\n \n \tfp = xfopen(*paths, \"r\");\n \n-\twhile (!strbuf_getline_crlf(&l1, fp)) {\n+\twhile (!strbuf_gets(&l1, fp)) {\n \t\tif (l1.len)\n \t\t\tbreak;\n \t}\n@@ -695,9 +680,9 @@ static int detect_patch_format(const char **paths)\n \t}\n \n \tstrbuf_reset(&l2);\n-\tstrbuf_getline_crlf(&l2, fp);\n+\tstrbuf_gets(&l2, fp);\n \tstrbuf_reset(&l3);\n-\tstrbuf_getline_crlf(&l3, fp);\n+\tstrbuf_gets(&l3, fp);\n \n \t/*\n \t * If the second line is empty and the third is a From, Author or Date\ndiff --git a/strbuf.c b/strbuf.c\nindex d76f0ae..290fc74 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -505,8 +505,20 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n-\tif (sb->buf[sb->len-1] == term)\n-\t\tstrbuf_setlen(sb, sb->len-1);\n+\tif (sb->buf[sb->len - 1] == term)\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n+\treturn 0;\n+}\n+\n+int strbuf_gets(struct strbuf *sb, FILE *fp)\n+{\n+\tif (strbuf_getwholeline(sb, fp, '\\n'))\n+\t\treturn EOF;\n+\tif (sb->buf[sb->len - 1] == '\\n') {\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t\tif (sb->len && sb->buf[sb->len - 1] == '\\r')\n+\t\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t}\n \treturn 0;\n }\n \ndiff --git a/strbuf.h b/strbuf.h\nindex 7123fca..c22bae0 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -388,6 +388,13 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  */\n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+/*\n+ * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n+ * and additionally treats a '\\r' that comes immediately before '\\n'\n+ * as part of the terminator.\n+ */\n+extern int strbuf_gets(struct strbuf *, FILE *);\n+\n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\n  * any) in the buffer.\n-- \n2.6.2-423-g5314b62\n"},{"id":"272458","messageId":"1446071161-15610-3-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 02/17] check-attr, check-ignore, checkout-index: read paths with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:46Z","receivedAt":"2015-10-28T22:25:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These commands read list of paths from their standard input under\nthe --stdin option (in order to avoid busting limit on the length of\nthe command line).\n\nWhen they are using text input mode (i.e. line_termination is set to\n'\\n'), we should try to be more friendly to our DOSsy friends and\naccept lines with CRLF endings.\n\nIt is tempting to lift this logic to strbuf_getline() and not\nintroduce a separate strbuf_gets(), but that can lead to silent\nmisconversion.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/check-attr.c     | 4 +++-\n builtin/check-ignore.c   | 5 ++++-\n builtin/checkout-index.c | 4 +++-\n 3 files changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 265c9ba..72d4bb6 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -77,7 +77,9 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n \n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\twhile ((line_termination\n+\t\t? strbuf_gets(&buf, stdin)\n+\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 43f3617..d36e9bf 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -122,7 +122,10 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n \n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\n+\twhile ((line_termination\n+\t\t? strbuf_gets(&buf, stdin)\n+\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 8028c37..8b6be57 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -258,7 +258,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\tif (all)\n \t\t\tdie(\"git checkout-index: don't mix '--all' and '--stdin'\");\n \n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\twhile ((line_termination\n+\t\t\t? strbuf_gets(&buf, stdin)\n+\t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n-- \n2.6.2-423-g5314b62\n"},{"id":"272445","messageId":"1446071161-15610-4-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 03/17] update-index: read --index-info with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:47Z","receivedAt":"2015-10-28T22:25:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/update-index.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 7431938..dfc65a8 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -473,7 +473,9 @@ static void read_index_info(int line_termination)\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf uq = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\twhile ((line_termination\n+\t\t? strbuf_gets(&buf, stdin)\n+\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tchar *ptr, *tab;\n \t\tchar *path_name;\n \t\tunsigned char sha1[20];\n-- \n2.6.2-423-g5314b62\n"},{"id":"272447","messageId":"1446071161-15610-5-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 04/17] update-index: read list of paths with strbuf_gets() under --stdin","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:48Z","receivedAt":"2015-10-28T22:25:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/update-index.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex dfc65a8..004871b 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -1075,7 +1075,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n \t\tsetup_work_tree();\n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\n+\t\twhile ((line_termination\n+\t\t\t? strbuf_gets(&buf, stdin)\n+\t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n-- \n2.6.2-423-g5314b62\n"},{"id":"272455","messageId":"1446071161-15610-6-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 05/17] mktree: read textual tree representation with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:49Z","receivedAt":"2015-10-28T22:25:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The input can come from a DOS editor.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mktree.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a964d6b..a55f067 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -157,7 +157,9 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n \n \twhile (!got_eof) {\n \t\twhile (1) {\n-\t\t\tif (strbuf_getline(&sb, stdin, line_termination) == EOF) {\n+\t\t\tif ((line_termination\n+\t\t\t     ? strbuf_gets(&sb, stdin)\n+\t\t\t     : strbuf_getline(&sb, stdin, '\\0')) == EOF) {\n \t\t\t\tgot_eof = 1;\n \t\t\t\tbreak;\n \t\t\t}\n-- \n2.6.2-423-g5314b62\n"},{"id":"272450","messageId":"1446071161-15610-7-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 06/17] hash-object: read --stdin-paths with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:50Z","receivedAt":"2015-10-28T22:25:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The list of paths could have been written with a DOS editor.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/hash-object.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 43b098b..46d55e5 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n {\n \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_gets(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n-- \n2.6.2-423-g5314b62\n"},{"id":"272443","messageId":"1446071161-15610-8-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 07/17] revision: read --stdin with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:51Z","receivedAt":"2015-10-28T22:25:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Reading with getwholeline() and manually stripping the terminating\n'\\n' would leave CR at the end of the line if the input comes from\na DOS editor.\n\nConstrasting this with the previous few changes, one may realize\nthat the way \"log\" family of commands read the paths with --stdin\nlooks inconsistent and sloppy.  It does not allow us to C-quote a\ntextual input, and it does not accept NUL-terminated records.  These\nare unfortunately way too late to fix X-<.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c | 9 ++-------\n 1 file changed, 2 insertions(+), 7 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 2236463..7d100d8 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1641,10 +1641,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av)\n static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n \t\t\t\t     struct cmdline_pathspec *prune)\n {\n-\twhile (strbuf_getwholeline(sb, stdin, '\\n') != EOF) {\n-\t\tint len = sb->len;\n-\t\tif (len && sb->buf[len - 1] == '\\n')\n-\t\t\tsb->buf[--len] = '\\0';\n+\twhile (strbuf_gets(sb, stdin) != EOF) {\n \t\tALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n \t\tprune->path[prune->nr++] = xstrdup(sb->buf);\n \t}\n@@ -1661,10 +1658,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \twarn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n-\twhile (strbuf_getwholeline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_gets(&sb, stdin) != EOF) {\n \t\tint len = sb.len;\n-\t\tif (len && sb.buf[len - 1] == '\\n')\n-\t\t\tsb.buf[--len] = '\\0';\n \t\tif (!len)\n \t\t\tbreak;\n \t\tif (sb.buf[0] == '-') {\n-- \n2.6.2-423-g5314b62\n"},{"id":"272448","messageId":"1446071161-15610-9-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 08/17] rev-parse: read parseopt spec with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:52Z","receivedAt":"2015-10-28T22:25:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"rev-parse --parseopt\" specification is clearly text and we\nshould anticipate that we may be fed CRLF lines.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/rev-parse.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 02d747d..5317389 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -386,7 +386,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \n \t/* get the usage up to the first line with a -- on it */\n \tfor (;;) {\n-\t\tif (strbuf_getline(&sb, stdin, '\\n') == EOF)\n+\t\tif (strbuf_gets(&sb, stdin) == EOF)\n \t\t\tdie(\"premature end of input\");\n \t\tALLOC_GROW(usage, unb + 1, usz);\n \t\tif (!strcmp(\"--\", sb.buf)) {\n@@ -399,7 +399,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_gets(&sb, stdin) != EOF) {\n \t\tconst char *s;\n \t\tconst char *help;\n \t\tstruct option *o;\n-- \n2.6.2-423-g5314b62\n"},{"id":"272444","messageId":"1446071161-15610-10-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 09/17] ident.c: read /etc/mailname with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:53Z","receivedAt":"2015-10-28T22:25:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Just in case /etc/mailname file was edited with a DOS editor,\nread it with strbuf_gets() so that a stray CR is not included\nas the last character of the mail hostname.\n\nWe _might_ want to more aggressively discard whitespace characters\naround the line with strbuf_trim(), but that is a bit outside the\nscope of this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n ident.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/ident.c b/ident.c\nindex 5ff1aad..c377f2b 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -55,7 +55,7 @@ static int add_mailname_host(struct strbuf *buf)\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\tif (strbuf_getline(&mailnamebuf, mailname, '\\n') == EOF) {\n+\tif (strbuf_gets(&mailnamebuf, mailname) == EOF) {\n \t\tif (ferror(mailname))\n \t\t\twarning(\"cannot read /etc/mailname: %s\",\n \t\t\t\tstrerror(errno));\n-- \n2.6.2-423-g5314b62\n"},{"id":"272457","messageId":"1446071161-15610-11-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 10/17] remote.c: read $GIT_DIR/remotes/* with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:54Z","receivedAt":"2015-10-28T22:25:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These files can be edited with a DOS editor, leaving CR at the end\nof the line if read with strbuf_getline().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/remote.c b/remote.c\nindex 1101f82..90eef22 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \tremote->origin = REMOTE_REMOTES;\n-\twhile (strbuf_getline(&buf, f, '\\n') != EOF) {\n+\twhile (strbuf_gets(&buf, f) != EOF) {\n \t\tconst char *v;\n \n \t\tstrbuf_rtrim(&buf);\n-- \n2.6.2-423-g5314b62\n"},{"id":"272446","messageId":"1446071161-15610-12-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 11/17] clone/sha1_file: read info/alternates with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:55Z","receivedAt":"2015-10-28T22:25:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"$GIT_OBJECT_DIRECTORY/info/alternates is a text file that can be\nedited with a DOS editor.  We do not want to use the real path with\nCR appeneded at the end.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/clone.c | 2 +-\n sha1_file.c     | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 9eaecd9..3d2615c 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n \tFILE *in = fopen(src->buf, \"r\");\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\twhile (strbuf_gets(&line, in) != EOF) {\n \t\tchar *abs_path;\n \t\tif (!line.len || line.buf[0] == '#')\n \t\t\tcontinue;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 50896ff..957178c 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -395,7 +395,7 @@ void add_to_alternates_file(const char *reference)\n \t\tstruct strbuf line = STRBUF_INIT;\n \t\tint found = 0;\n \n-\t\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\t\twhile (strbuf_gets(&line, in) != EOF) {\n \t\t\tif (!strcmp(reference, line.buf)) {\n \t\t\t\tfound = 1;\n \t\t\t\tbreak;\n-- \n2.6.2-423-g5314b62\n"},{"id":"272451","messageId":"1446071161-15610-13-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 12/17] transport-helper: read helper response with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:56Z","receivedAt":"2015-10-28T22:25:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Our implementation of helpers never use CRLF line endings, and they\ndo not depend on the ability to place a CR as payload at the end of\nthe line, so this is essentially a no-op for in-tree users.  However,\nthis allows third-party implementation of helpers to give us their\nline with CRLF line ending (they cannot expect us to feed CRLF to\nthem, though).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n transport-helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/transport-helper.c b/transport-helper.c\nindex 63d5427..e0e1c9c 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)\n \tstrbuf_reset(buffer);\n \tif (debug)\n \t\tfprintf(stderr, \"Debug: Remote helper: Waiting...\\n\");\n-\tif (strbuf_getline(buffer, helper, '\\n') == EOF) {\n+\tif (strbuf_gets(buffer, helper) == EOF) {\n \t\tif (debug)\n \t\t\tfprintf(stderr, \"Debug: Remote helper quit.\\n\");\n \t\treturn 1;\n-- \n2.6.2-423-g5314b62\n"},{"id":"272452","messageId":"1446071161-15610-14-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 13/17] cat-file: read batch stream with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:57Z","receivedAt":"2015-10-28T22:25:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"It is possible to prepare a text file with a DOS editor and feed it\nas a batch command stream to the command.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/cat-file.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex c0fd8db..e79097d 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n \tsave_warning = warn_on_object_refname_ambiguity;\n \twarn_on_object_refname_ambiguity = 0;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_gets(&buf, stdin) != EOF) {\n \t\tif (data.split_on_whitespace) {\n \t\t\t/*\n \t\t\t * Split at first whitespace, tying off the beginning\n-- \n2.6.2-423-g5314b62\n"},{"id":"272456","messageId":"1446071161-15610-15-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 14/17] column: read lines with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:58Z","receivedAt":"2015-10-28T22:25:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Multiple lines read here are concatenated on a single line to form a\nmulti-column output line.  We do not want to have a CR at the end,\neven if the input file consists of CRLF terminated lines.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/column.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 449413c..e9fe928 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--command must be the first argument\"));\n \t}\n \tfinalize_colopts(&colopts, -1);\n-\twhile (!strbuf_getline(&sb, stdin, '\\n'))\n+\twhile (!strbuf_gets(&sb, stdin))\n \t\tstring_list_append(&list, sb.buf);\n \n \tprint_columns(&list, colopts, &copts);\n-- \n2.6.2-423-g5314b62\n"},{"id":"272449","messageId":"1446071161-15610-16-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 15/17] send-pack: read list of refs with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:25:59Z","receivedAt":"2015-10-28T22:25:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/send-pack.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex f6e5d64..ba318c9 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targv_array_push(&all_refspecs, buf);\n \t\t} else {\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline(&line, stdin, '\\n') != EOF)\n+\t\t\twhile (strbuf_gets(&line, stdin) != EOF)\n \t\t\t\targv_array_push(&all_refspecs, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\n-- \n2.6.2-423-g5314b62\n"},{"id":"272441","messageId":"1446071161-15610-17-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 16/17] grep: read -f file with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:26:00Z","receivedAt":"2015-10-28T22:26:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"List of patterns file could come from a DOS editor.\n\nThis is iffy; you may actually be trying to find a line with ^M in\nit on a system whose line ending is LF.  You can of course work it\naround by having a line that has \"^M^M^J\", let the strbuf_gets() eat\nthe last \"^M^J\", leaving just the single \"^M\" as the pattern.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/grep.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d04f440..ac27690 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -562,7 +562,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n-\twhile (strbuf_getline(&sb, patterns, '\\n') == 0) {\n+\twhile (strbuf_gets(&sb, patterns) == 0) {\n \t\t/* ignore empty line like grep does */\n \t\tif (sb.len == 0)\n \t\t\tcontinue;\n-- \n2.6.2-423-g5314b62\n"},{"id":"272454","messageId":"1446071161-15610-18-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH 17/17] test-sha1-array: read command stream with strbuf_gets()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T22:26:01Z","receivedAt":"2015-10-28T22:26:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The input to this command comes from a pipeline in t0064, whose\nupstream has bunch of \"echo\"s.  It is not unreasonable to expect\nthat it may be fed CRLF lines on DOSsy systems.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n test-sha1-array.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/test-sha1-array.c b/test-sha1-array.c\nindex ddc491e..46ff240 100644\n--- a/test-sha1-array.c\n+++ b/test-sha1-array.c\n@@ -11,7 +11,7 @@ int main(int argc, char **argv)\n \tstruct sha1_array array = SHA1_ARRAY_INIT;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, stdin, '\\n') != EOF) {\n+\twhile (strbuf_gets(&line, stdin) != EOF) {\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n \n-- \n2.6.2-423-g5314b62\n"},{"id":"274629","messageId":"1450303398-25900-1-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1446071161-15610-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 00/17] Peace with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:01Z","receivedAt":"2015-12-16T22:03:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We have too many topics titled \"War on something\"; let's try to make\npeace for a change.\n\nThis is a reroll with small changes of the previous one that appears\nhere:\n\n  http://thread.gmane.org/gmane.comp.version-control.git/280401\n\nwhich is a continuation to $gmane/275735, which is filed in the\narchive under another mailing list:\n\n  http://thread.gmane.org/gmane.comp.version-control.msysgit/21773\n\nWe read \"text\" files from filesystem (or from the standard input) in\nvarious places in the code.  Some of them are written by us, but\nothers are often prepared by an editor driven by human user.  Even\nthough we write (and expect) lines in these text files to be\nterminated with LF (not CRLF), the end-user's editor can be told to\nuse CRLF termination, and on some platforms that may be the default.\n\nBecause many codepaths (e.g. commit log message) first pass the\ncontents of such a file through stripspace(), and as a side effect\nof discarding the whitespace at the end of each line, lines\nterminated with CRLF are normalized to LF terminated lines (but we\ndo not lose a lone CR in the middle of a non-blank string), this is\nnot a problem in many codepaths.  But not all of the codepaths are\nsafe.\n\nTypically, we use strbuf_getline() to read these \"text\" files, which\nreads a single line up to the first LF into a buffer, discard that\nLF at the end, and returns (an incomplete last line gets returned\nas-is).  In theory, these places that expect to read \"text\", we\nshould be able to update the logic to read a line up to the first\nLF, discard that LF, together with a CR if one appears immediately\nbefore that LF, without breaking anything.\n\nI inspected all the callsites of this function to see if it is safe\nto use such an updated logic at these callsites, and did not find\nanything problematic.  I could update strbuf_getline() in place, but\njust to be extra careful, this series instead introduces another\nhelper, strbuf_getline_crlf(), that is aware of this CRLF business,\nand convert the ones that are safe to update as we verify.\n\n * This series converts only the callers of strbuf_getline() that\n   would misbehave when fed a file with CRLF-terminated lines and\n   use the data with an unwanted CR appended at the end.  With the\n   update the code should work as intended with such a file, without\n   breaking the expected behaviour when working on a file with\n   LF-terminated lines.\n\n * Callers of strbuf_getline() that expect to only read from our own\n   output do not have to accommodate CRLF-terminated lines, but they\n   can be updated to do so safely if we do not rely on the ability\n   to express a payload that has CR at the end.  For example, the\n   insn sheet \"rebase -i\" uses typically ends each line with a\n   commit log summary that we ourselves do not read or use, so even\n   if the end-user on a platform with LF lines deliberately does\n   insert \\r at the end of the line and strbuf_gets() removed that\n   \\r from the payload, no unexpected behaviour should happen.\n\n   This series does not touch them, but it may be a good GSoC\n   microproject to convert them to use strbuf_getline_crlf().\n\n * Callers of strbuf_getline() that call strbuf_trim() immediately\n   on the result before doing anything, or otherwise have logic that\n   tolerates whitespaces at the end of the line, can continue using\n   strbuf_getline() and will not misbehave on CRLF-terminated lines.\n\n   This series does not touch them; converting them to use\n   strbuf_getline_crlf() would a good way to document them as\n   dealing with \"text\".  While doing so, they can also lose their\n   custom logic that happens to make CRLF-terminated lines work.\n\n * A caller of strbuf_getline() that wants to only see LF-terminated\n   lines (in other words, \"ABC\\r\\n\" must be treated as a line with 4\n   bytes payload on it, A B C and CR), would be broken if we replace\n   it with strbuf_getline_crlf().  This series does not touch them,\n   and no follow-up series should, either.\n\nAn ideal endgame would be to retire the current strbuf_getline() and\nuse strbuf_getline_crlf() everywhere.  For that to happen, follow-up\ntopics to cover the second and the third class of callers above need\nto show that there is no remaining callers to strbuf_getline() that\nfalls into the fourth category.\n\nEven better, once you say \"line\", as in strbuf_getline(), you ought\nto be talking about \"text\", so we could rename strbuf_getline_crlf()\nback to strbuf_getline() after all of the above happens.\n\n\nJunio C Hamano (17):\n  strbuf: make strbuf_getline_crlf() global\n  check-attr, check-ignore, checkout-index: read paths with\n    strbuf_getline_crlf()\n  update-index: read --index-info with strbuf_getline_crlf()\n  update-index: read list of paths with strbuf_getline_crlf() under\n    --stdin\n  mktree: read textual tree representation with strbuf_getline_crlf()\n  hash-object: read --stdin-paths with strbuf_getline_crlf()\n  revision: read --stdin with strbuf_getline_crlf()\n  rev-parse: read parseopt spec with strbuf_getline_crlf()\n  ident.c: read /etc/mailname with strbuf_getline_crlf()\n  remote.c: read $GIT_DIR/remotes/* with strbuf_getline_crlf()\n  clone/sha1_file: read info/alternates with strbuf_getline_crlf()\n  transport-helper: read helper response with strbuf_getline_crlf()\n  cat-file: read batch stream with strbuf_getline_crlf()\n  column: read lines with strbuf_getline_crlf()\n  send-pack: read list of refs with strbuf_getline_crlf()\n  grep: read -f file with strbuf_getline_crlf()\n  test-sha1-array: read command stream with strbuf_getline_crlf()\n\n builtin/am.c             | 15 ---------------\n builtin/cat-file.c       |  2 +-\n builtin/check-attr.c     |  4 +++-\n builtin/check-ignore.c   |  5 ++++-\n builtin/checkout-index.c |  4 +++-\n builtin/clone.c          |  2 +-\n builtin/column.c         |  2 +-\n builtin/grep.c           |  2 +-\n builtin/hash-object.c    |  2 +-\n builtin/mktree.c         |  4 +++-\n builtin/rev-parse.c      |  4 ++--\n builtin/send-pack.c      |  2 +-\n builtin/update-index.c   |  9 +++++++--\n ident.c                  |  2 +-\n remote.c                 |  2 +-\n revision.c               |  9 ++-------\n sha1_file.c              |  2 +-\n strbuf.c                 | 16 ++++++++++++++--\n strbuf.h                 |  7 +++++++\n test-sha1-array.c        |  2 +-\n transport-helper.c       |  2 +-\n 21 files changed, 56 insertions(+), 43 deletions(-)\n\n-- \n2.7.0-rc1-83-ga8b6b9e\n\n\nThe interdiff between this round and v1 follows.\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 9376d5e..94a533a 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -612,7 +612,7 @@ static int is_mail(FILE *fp)\n \tif (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))\n \t\tdie(\"invalid pattern: %s\", header_regex);\n \n-\twhile (!strbuf_gets(&sb, fp)) {\n+\twhile (!strbuf_getline_crlf(&sb, fp)) {\n \t\tif (!sb.len)\n \t\t\tbreak; /* End of header */\n \n@@ -659,7 +659,7 @@ static int detect_patch_format(const char **paths)\n \n \tfp = xfopen(*paths, \"r\");\n \n-\twhile (!strbuf_gets(&l1, fp)) {\n+\twhile (!strbuf_getline_crlf(&l1, fp)) {\n \t\tif (l1.len)\n \t\t\tbreak;\n \t}\n@@ -680,9 +680,9 @@ static int detect_patch_format(const char **paths)\n \t}\n \n \tstrbuf_reset(&l2);\n-\tstrbuf_gets(&l2, fp);\n+\tstrbuf_getline_crlf(&l2, fp);\n \tstrbuf_reset(&l3);\n-\tstrbuf_gets(&l3, fp);\n+\tstrbuf_getline_crlf(&l3, fp);\n \n \t/*\n \t * If the second line is empty and the third is a From, Author or Date\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex e79097d..a2e75ad 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n \tsave_warning = warn_on_object_refname_ambiguity;\n \twarn_on_object_refname_ambiguity = 0;\n \n-\twhile (strbuf_gets(&buf, stdin) != EOF) {\n+\twhile (strbuf_getline_crlf(&buf, stdin) != EOF) {\n \t\tif (data.split_on_whitespace) {\n \t\t\t/*\n \t\t\t * Split at first whitespace, tying off the beginning\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 72d4bb6..4c44d8f 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -78,7 +78,7 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n \twhile ((line_termination\n-\t\t? strbuf_gets(&buf, stdin)\n+\t\t? strbuf_getline_crlf(&buf, stdin)\n \t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex d36e9bf..862ced1 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -124,7 +124,7 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n \tstrbuf_init(&nbuf, 0);\n \n \twhile ((line_termination\n-\t\t? strbuf_gets(&buf, stdin)\n+\t\t? strbuf_getline_crlf(&buf, stdin)\n \t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 8b6be57..27d65f2 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -259,7 +259,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"git checkout-index: don't mix '--all' and '--stdin'\");\n \n \t\twhile ((line_termination\n-\t\t\t? strbuf_gets(&buf, stdin)\n+\t\t\t? strbuf_getline_crlf(&buf, stdin)\n \t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 3d2615c..0a85243 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n \tFILE *in = fopen(src->buf, \"r\");\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_gets(&line, in) != EOF) {\n+\twhile (strbuf_getline_crlf(&line, in) != EOF) {\n \t\tchar *abs_path;\n \t\tif (!line.len || line.buf[0] == '#')\n \t\t\tcontinue;\ndiff --git a/builtin/column.c b/builtin/column.c\nindex e9fe928..3205aa9 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--command must be the first argument\"));\n \t}\n \tfinalize_colopts(&colopts, -1);\n-\twhile (!strbuf_gets(&sb, stdin))\n+\twhile (!strbuf_getline_crlf(&sb, stdin))\n \t\tstring_list_append(&list, sb.buf);\n \n \tprint_columns(&list, colopts, &copts);\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex ac27690..df162f1 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -562,7 +562,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n-\twhile (strbuf_gets(&sb, patterns) == 0) {\n+\twhile (strbuf_getline_crlf(&sb, patterns) == 0) {\n \t\t/* ignore empty line like grep does */\n \t\tif (sb.len == 0)\n \t\t\tcontinue;\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 46d55e5..57c743d 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n {\n \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n-\twhile (strbuf_gets(&buf, stdin) != EOF) {\n+\twhile (strbuf_getline_crlf(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a55f067..c6cafb6 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -158,7 +158,7 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n \twhile (!got_eof) {\n \t\twhile (1) {\n \t\t\tif ((line_termination\n-\t\t\t     ? strbuf_gets(&sb, stdin)\n+\t\t\t     ? strbuf_getline_crlf(&sb, stdin)\n \t\t\t     : strbuf_getline(&sb, stdin, '\\0')) == EOF) {\n \t\t\t\tgot_eof = 1;\n \t\t\t\tbreak;\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 5317389..f2cf99c 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -386,7 +386,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \n \t/* get the usage up to the first line with a -- on it */\n \tfor (;;) {\n-\t\tif (strbuf_gets(&sb, stdin) == EOF)\n+\t\tif (strbuf_getline_crlf(&sb, stdin) == EOF)\n \t\t\tdie(\"premature end of input\");\n \t\tALLOC_GROW(usage, unb + 1, usz);\n \t\tif (!strcmp(\"--\", sb.buf)) {\n@@ -399,7 +399,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */\n-\twhile (strbuf_gets(&sb, stdin) != EOF) {\n+\twhile (strbuf_getline_crlf(&sb, stdin) != EOF) {\n \t\tconst char *s;\n \t\tconst char *help;\n \t\tstruct option *o;\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex ba318c9..02e6e24 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targv_array_push(&all_refspecs, buf);\n \t\t} else {\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_gets(&line, stdin) != EOF)\n+\t\t\twhile (strbuf_getline_crlf(&line, stdin) != EOF)\n \t\t\t\targv_array_push(&all_refspecs, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 004871b..3a6c5b2 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -474,7 +474,7 @@ static void read_index_info(int line_termination)\n \tstruct strbuf uq = STRBUF_INIT;\n \n \twhile ((line_termination\n-\t\t? strbuf_gets(&buf, stdin)\n+\t\t? strbuf_getline_crlf(&buf, stdin)\n \t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tchar *ptr, *tab;\n \t\tchar *path_name;\n@@ -1077,7 +1077,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\tsetup_work_tree();\n \n \t\twhile ((line_termination\n-\t\t\t? strbuf_gets(&buf, stdin)\n+\t\t\t? strbuf_getline_crlf(&buf, stdin)\n \t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\ndiff --git a/ident.c b/ident.c\nindex c377f2b..9018df0 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -55,7 +55,7 @@ static int add_mailname_host(struct strbuf *buf)\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\tif (strbuf_gets(&mailnamebuf, mailname) == EOF) {\n+\tif (strbuf_getline_crlf(&mailnamebuf, mailname) == EOF) {\n \t\tif (ferror(mailname))\n \t\t\twarning(\"cannot read /etc/mailname: %s\",\n \t\t\t\tstrerror(errno));\ndiff --git a/remote.c b/remote.c\nindex 90eef22..e88d936 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \tremote->origin = REMOTE_REMOTES;\n-\twhile (strbuf_gets(&buf, f) != EOF) {\n+\twhile (strbuf_getline_crlf(&buf, f) != EOF) {\n \t\tconst char *v;\n \n \t\tstrbuf_rtrim(&buf);\ndiff --git a/revision.c b/revision.c\nindex 7d100d8..651a34b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1641,7 +1641,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av)\n static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n \t\t\t\t     struct cmdline_pathspec *prune)\n {\n-\twhile (strbuf_gets(sb, stdin) != EOF) {\n+\twhile (strbuf_getline_crlf(sb, stdin) != EOF) {\n \t\tALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n \t\tprune->path[prune->nr++] = xstrdup(sb->buf);\n \t}\n@@ -1658,7 +1658,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \twarn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n-\twhile (strbuf_gets(&sb, stdin) != EOF) {\n+\twhile (strbuf_getline_crlf(&sb, stdin) != EOF) {\n \t\tint len = sb.len;\n \t\tif (!len)\n \t\t\tbreak;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 957178c..7a748f2 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -395,7 +395,7 @@ void add_to_alternates_file(const char *reference)\n \t\tstruct strbuf line = STRBUF_INIT;\n \t\tint found = 0;\n \n-\t\twhile (strbuf_gets(&line, in) != EOF) {\n+\t\twhile (strbuf_getline_crlf(&line, in) != EOF) {\n \t\t\tif (!strcmp(reference, line.buf)) {\n \t\t\t\tfound = 1;\n \t\t\t\tbreak;\ndiff --git a/strbuf.c b/strbuf.c\nindex 290fc74..7ad5ea4 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -510,7 +510,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n \treturn 0;\n }\n \n-int strbuf_gets(struct strbuf *sb, FILE *fp)\n+int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n {\n \tif (strbuf_getwholeline(sb, fp, '\\n'))\n \t\treturn EOF;\ndiff --git a/strbuf.h b/strbuf.h\nindex c22bae0..d84c866 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -393,7 +393,7 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);\n  * and additionally treats a '\\r' that comes immediately before '\\n'\n  * as part of the terminator.\n  */\n-extern int strbuf_gets(struct strbuf *, FILE *);\n+extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n \n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\ndiff --git a/test-sha1-array.c b/test-sha1-array.c\nindex 46ff240..87b04de 100644\n--- a/test-sha1-array.c\n+++ b/test-sha1-array.c\n@@ -11,7 +11,7 @@ int main(int argc, char **argv)\n \tstruct sha1_array array = SHA1_ARRAY_INIT;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_gets(&line, stdin) != EOF) {\n+\twhile (strbuf_getline_crlf(&line, stdin) != EOF) {\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex e0e1c9c..7de52e1 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)\n \tstrbuf_reset(buffer);\n \tif (debug)\n \t\tfprintf(stderr, \"Debug: Remote helper: Waiting...\\n\");\n-\tif (strbuf_gets(buffer, helper) == EOF) {\n+\tif (strbuf_getline_crlf(buffer, helper) == EOF) {\n \t\tif (debug)\n \t\t\tfprintf(stderr, \"Debug: Remote helper quit.\\n\");\n \t\treturn 1;\n"},{"id":"274612","messageId":"1450303398-25900-2-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 01/17] strbuf: make strbuf_getline_crlf() global","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:02Z","receivedAt":"2015-12-16T22:03:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Often we read \"text\" files that are supplied by the end user\n(e.g. commit log message that was edited with $GIT_EDITOR upon\n'git commit -e'), and in some environments lines in a text file\nare terminated with CRLF.  Existing strbuf_getline() knows to read\na single line and then strip the terminating byte from the result,\nbut it is handy to have a version that is more tailored for a \"text\"\ninput that takes both '\\n' and '\\r\\n' as line terminator (aka\n<newline> in POSIX lingo) and returns the body of the line after\nstripping <newline>.\n\nRecently reimplemented \"git am\" uses such a function implemented\nprivately; move it to strbuf.[ch] and make it available for others.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 15 ---------------\n strbuf.c     | 16 ++++++++++++++--\n strbuf.h     |  7 +++++++\n 3 files changed, 21 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 4e396c8..94a533a 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -45,21 +45,6 @@ static int is_empty_file(const char *filename)\n }\n \n /**\n- * Like strbuf_getline(), but treats both '\\n' and \"\\r\\n\" as line terminators.\n- */\n-static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n-{\n-\tif (strbuf_getwholeline(sb, fp, '\\n'))\n-\t\treturn EOF;\n-\tif (sb->buf[sb->len - 1] == '\\n') {\n-\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t\tif (sb->len > 0 && sb->buf[sb->len - 1] == '\\r')\n-\t\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n  * Returns the length of the first line of msg.\n  */\n static int linelen(const char *msg)\ndiff --git a/strbuf.c b/strbuf.c\nindex d76f0ae..7ad5ea4 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -505,8 +505,20 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n-\tif (sb->buf[sb->len-1] == term)\n-\t\tstrbuf_setlen(sb, sb->len-1);\n+\tif (sb->buf[sb->len - 1] == term)\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n+\treturn 0;\n+}\n+\n+int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n+{\n+\tif (strbuf_getwholeline(sb, fp, '\\n'))\n+\t\treturn EOF;\n+\tif (sb->buf[sb->len - 1] == '\\n') {\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t\tif (sb->len && sb->buf[sb->len - 1] == '\\r')\n+\t\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t}\n \treturn 0;\n }\n \ndiff --git a/strbuf.h b/strbuf.h\nindex 7123fca..d84c866 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -388,6 +388,13 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  */\n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+/*\n+ * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n+ * and additionally treats a '\\r' that comes immediately before '\\n'\n+ * as part of the terminator.\n+ */\n+extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n+\n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\n  * any) in the buffer.\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274613","messageId":"1450303398-25900-3-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 02/17] check-attr, check-ignore, checkout-index: read paths with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:03Z","receivedAt":"2015-12-16T22:03:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These commands read list of paths from their standard input under\nthe --stdin option (in order to avoid busting limit on the length of\nthe command line).\n\nWhen they are using text input mode (i.e. line_termination is set to\n'\\n'), we should try to be more friendly to our DOSsy friends and\naccept lines with CRLF endings.\n\nIt is tempting to lift this logic to strbuf_getline() and not\nintroduce a separate strbuf_getline_crlf(), but that can lead to silent\nmisconversion.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/check-attr.c     | 4 +++-\n builtin/check-ignore.c   | 5 ++++-\n builtin/checkout-index.c | 4 +++-\n 3 files changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 265c9ba..4c44d8f 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -77,7 +77,9 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n \n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\twhile ((line_termination\n+\t\t? strbuf_getline_crlf(&buf, stdin)\n+\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 43f3617..862ced1 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -122,7 +122,10 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n \n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\n+\twhile ((line_termination\n+\t\t? strbuf_getline_crlf(&buf, stdin)\n+\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 8028c37..27d65f2 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -258,7 +258,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\tif (all)\n \t\t\tdie(\"git checkout-index: don't mix '--all' and '--stdin'\");\n \n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\twhile ((line_termination\n+\t\t\t? strbuf_getline_crlf(&buf, stdin)\n+\t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274614","messageId":"1450303398-25900-4-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 03/17] update-index: read --index-info with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:04Z","receivedAt":"2015-12-16T22:03:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/update-index.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 7431938..a7a9a7e 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -473,7 +473,9 @@ static void read_index_info(int line_termination)\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf uq = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\twhile ((line_termination\n+\t\t? strbuf_getline_crlf(&buf, stdin)\n+\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\tchar *ptr, *tab;\n \t\tchar *path_name;\n \t\tunsigned char sha1[20];\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274616","messageId":"1450303398-25900-5-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 04/17] update-index: read list of paths with strbuf_getline_crlf() under --stdin","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:05Z","receivedAt":"2015-12-16T22:03:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/update-index.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex a7a9a7e..3a6c5b2 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -1075,7 +1075,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n \t\tsetup_work_tree();\n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\n+\t\twhile ((line_termination\n+\t\t\t? strbuf_getline_crlf(&buf, stdin)\n+\t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274627","messageId":"1450303398-25900-6-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 05/17] mktree: read textual tree representation with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:06Z","receivedAt":"2015-12-16T22:03:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The input can come from a DOS editor.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mktree.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a964d6b..c6cafb6 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -157,7 +157,9 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n \n \twhile (!got_eof) {\n \t\twhile (1) {\n-\t\t\tif (strbuf_getline(&sb, stdin, line_termination) == EOF) {\n+\t\t\tif ((line_termination\n+\t\t\t     ? strbuf_getline_crlf(&sb, stdin)\n+\t\t\t     : strbuf_getline(&sb, stdin, '\\0')) == EOF) {\n \t\t\t\tgot_eof = 1;\n \t\t\t\tbreak;\n \t\t\t}\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274628","messageId":"1450303398-25900-7-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 06/17] hash-object: read --stdin-paths with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:07Z","receivedAt":"2015-12-16T22:03:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The list of paths could have been written with a DOS editor.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/hash-object.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 43b098b..57c743d 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n {\n \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274615","messageId":"1450303398-25900-8-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 07/17] revision: read --stdin with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:08Z","receivedAt":"2015-12-16T22:03:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Reading with getwholeline() and manually stripping the terminating\n'\\n' would leave CR at the end of the line if the input comes from\na DOS editor.\n\nContrasting this with the previous few changes, one may realize that\nthe way \"log\" family of commands read the paths with --stdin looks\ninconsistent and sloppy.  It does not allow us to C-quote a textual\ninput, and it does not accept NUL-terminated records.  These are\nunfortunately way too late to fix X-<.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c | 9 ++-------\n 1 file changed, 2 insertions(+), 7 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 2236463..651a34b 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1641,10 +1641,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av)\n static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n \t\t\t\t     struct cmdline_pathspec *prune)\n {\n-\twhile (strbuf_getwholeline(sb, stdin, '\\n') != EOF) {\n-\t\tint len = sb->len;\n-\t\tif (len && sb->buf[len - 1] == '\\n')\n-\t\t\tsb->buf[--len] = '\\0';\n+\twhile (strbuf_getline_crlf(sb, stdin) != EOF) {\n \t\tALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n \t\tprune->path[prune->nr++] = xstrdup(sb->buf);\n \t}\n@@ -1661,10 +1658,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \twarn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n-\twhile (strbuf_getwholeline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&sb, stdin) != EOF) {\n \t\tint len = sb.len;\n-\t\tif (len && sb.buf[len - 1] == '\\n')\n-\t\t\tsb.buf[--len] = '\\0';\n \t\tif (!len)\n \t\t\tbreak;\n \t\tif (sb.buf[0] == '-') {\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274617","messageId":"1450303398-25900-9-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 08/17] rev-parse: read parseopt spec with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:09Z","receivedAt":"2015-12-16T22:03:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"rev-parse --parseopt\" specification is clearly text and we\nshould anticipate that we may be fed CRLF lines.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/rev-parse.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 02d747d..f2cf99c 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -386,7 +386,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \n \t/* get the usage up to the first line with a -- on it */\n \tfor (;;) {\n-\t\tif (strbuf_getline(&sb, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_crlf(&sb, stdin) == EOF)\n \t\t\tdie(\"premature end of input\");\n \t\tALLOC_GROW(usage, unb + 1, usz);\n \t\tif (!strcmp(\"--\", sb.buf)) {\n@@ -399,7 +399,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&sb, stdin) != EOF) {\n \t\tconst char *s;\n \t\tconst char *help;\n \t\tstruct option *o;\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274618","messageId":"1450303398-25900-10-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 09/17] ident.c: read /etc/mailname with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:10Z","receivedAt":"2015-12-16T22:03:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Just in case /etc/mailname file was edited with a DOS editor,\nread it with strbuf_getline_crlf() so that a stray CR is not included\nas the last character of the mail hostname.\n\nWe _might_ want to more aggressively discard whitespace characters\naround the line with strbuf_trim(), but that is a bit outside the\nscope of this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n ident.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/ident.c b/ident.c\nindex 5ff1aad..9018df0 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -55,7 +55,7 @@ static int add_mailname_host(struct strbuf *buf)\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\tif (strbuf_getline(&mailnamebuf, mailname, '\\n') == EOF) {\n+\tif (strbuf_getline_crlf(&mailnamebuf, mailname) == EOF) {\n \t\tif (ferror(mailname))\n \t\t\twarning(\"cannot read /etc/mailname: %s\",\n \t\t\t\tstrerror(errno));\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274626","messageId":"1450303398-25900-11-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 10/17] remote.c: read $GIT_DIR/remotes/* with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:11Z","receivedAt":"2015-12-16T22:03:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These files can be edited with a DOS editor, leaving CR at the end\nof the line if read with strbuf_getline().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/remote.c b/remote.c\nindex 1101f82..e88d936 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \tremote->origin = REMOTE_REMOTES;\n-\twhile (strbuf_getline(&buf, f, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&buf, f) != EOF) {\n \t\tconst char *v;\n \n \t\tstrbuf_rtrim(&buf);\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274622","messageId":"1450303398-25900-12-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 11/17] clone/sha1_file: read info/alternates with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:12Z","receivedAt":"2015-12-16T22:03:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"$GIT_OBJECT_DIRECTORY/info/alternates is a text file that can be\nedited with a DOS editor.  We do not want to use the real path with\nCR appended at the end.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/clone.c | 2 +-\n sha1_file.c     | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 9eaecd9..0a85243 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n \tFILE *in = fopen(src->buf, \"r\");\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&line, in) != EOF) {\n \t\tchar *abs_path;\n \t\tif (!line.len || line.buf[0] == '#')\n \t\t\tcontinue;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 50896ff..7a748f2 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -395,7 +395,7 @@ void add_to_alternates_file(const char *reference)\n \t\tstruct strbuf line = STRBUF_INIT;\n \t\tint found = 0;\n \n-\t\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_crlf(&line, in) != EOF) {\n \t\t\tif (!strcmp(reference, line.buf)) {\n \t\t\t\tfound = 1;\n \t\t\t\tbreak;\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274620","messageId":"1450303398-25900-13-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 12/17] transport-helper: read helper response with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:13Z","receivedAt":"2015-12-16T22:03:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Our implementation of helpers never use CRLF line endings, and they\ndo not depend on the ability to place a CR as payload at the end of\nthe line, so this is essentially a no-op for in-tree users.  However,\nthis allows third-party implementation of helpers to give us their\nline with CRLF line ending (they cannot expect us to feed CRLF to\nthem, though).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n transport-helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/transport-helper.c b/transport-helper.c\nindex 63d5427..7de52e1 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)\n \tstrbuf_reset(buffer);\n \tif (debug)\n \t\tfprintf(stderr, \"Debug: Remote helper: Waiting...\\n\");\n-\tif (strbuf_getline(buffer, helper, '\\n') == EOF) {\n+\tif (strbuf_getline_crlf(buffer, helper) == EOF) {\n \t\tif (debug)\n \t\t\tfprintf(stderr, \"Debug: Remote helper quit.\\n\");\n \t\treturn 1;\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274625","messageId":"1450303398-25900-14-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 13/17] cat-file: read batch stream with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:14Z","receivedAt":"2015-12-16T22:03:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"It is possible to prepare a text file with a DOS editor and feed it\nas a batch command stream to the command.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/cat-file.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex c0fd8db..a2e75ad 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n \tsave_warning = warn_on_object_refname_ambiguity;\n \twarn_on_object_refname_ambiguity = 0;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&buf, stdin) != EOF) {\n \t\tif (data.split_on_whitespace) {\n \t\t\t/*\n \t\t\t * Split at first whitespace, tying off the beginning\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274624","messageId":"1450303398-25900-15-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 14/17] column: read lines with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:15Z","receivedAt":"2015-12-16T22:03:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Multiple lines read here are concatenated on a single line to form a\nmulti-column output line.  We do not want to have a CR at the end,\neven if the input file consists of CRLF terminated lines.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/column.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 449413c..3205aa9 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--command must be the first argument\"));\n \t}\n \tfinalize_colopts(&colopts, -1);\n-\twhile (!strbuf_getline(&sb, stdin, '\\n'))\n+\twhile (!strbuf_getline_crlf(&sb, stdin))\n \t\tstring_list_append(&list, sb.buf);\n \n \tprint_columns(&list, colopts, &copts);\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274623","messageId":"1450303398-25900-16-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 15/17] send-pack: read list of refs with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:16Z","receivedAt":"2015-12-16T22:03:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/send-pack.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex f6e5d64..02e6e24 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targv_array_push(&all_refspecs, buf);\n \t\t} else {\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline(&line, stdin, '\\n') != EOF)\n+\t\t\twhile (strbuf_getline_crlf(&line, stdin) != EOF)\n \t\t\t\targv_array_push(&all_refspecs, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274619","messageId":"1450303398-25900-17-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 16/17] grep: read -f file with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:17Z","receivedAt":"2015-12-16T22:03:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"List of patterns file could come from a DOS editor.\n\nThis is iffy; you may actually be trying to find a line with ^M in\nit on a system whose line ending is LF.  You can of course work it\naround by having a line that has \"^M^M^J\", let the strbuf_getline_crlf() eat\nthe last \"^M^J\", leaving just the single \"^M\" as the pattern.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/grep.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d04f440..df162f1 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -562,7 +562,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n-\twhile (strbuf_getline(&sb, patterns, '\\n') == 0) {\n+\twhile (strbuf_getline_crlf(&sb, patterns) == 0) {\n \t\t/* ignore empty line like grep does */\n \t\tif (sb.len == 0)\n \t\t\tcontinue;\n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"274621","messageId":"1450303398-25900-18-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 17/17] test-sha1-array: read command stream with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T22:03:18Z","receivedAt":"2015-12-16T22:03:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The input to this command comes from a pipeline in t0064, whose\nupstream has bunch of \"echo\"s.  It is not unreasonable to expect\nthat it may be fed CRLF lines on DOSsy systems.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n test-sha1-array.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/test-sha1-array.c b/test-sha1-array.c\nindex ddc491e..87b04de 100644\n--- a/test-sha1-array.c\n+++ b/test-sha1-array.c\n@@ -11,7 +11,7 @@ int main(int argc, char **argv)\n \tstruct sha1_array array = SHA1_ARRAY_INIT;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_crlf(&line, stdin) != EOF) {\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n \n-- \n2.7.0-rc1-83-ga8b6b9e\n"},{"id":"275298","messageId":"alpine.DEB.2.20.1601041244370.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 00/17] Peace with CRLF","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:25:28Z","receivedAt":"2016-01-04T12:25:28Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> I inspected all the callsites of this function to see if it is safe\n> to use such an updated logic at these callsites, and did not find\n> anything problematic.  I could update strbuf_getline() in place, but\n> just to be extra careful, this series instead introduces another\n> helper, strbuf_getline_crlf(), that is aware of this CRLF business,\n> and convert the ones that are safe to update as we verify.\n> \n>  * This series converts only the callers of strbuf_getline() that\n>    would misbehave when fed a file with CRLF-terminated lines and\n>    use the data with an unwanted CR appended at the end.  With the\n>    update the code should work as intended with such a file, without\n>    breaking the expected behaviour when working on a file with\n>    LF-terminated lines.\n> \n>  * Callers of strbuf_getline() that expect to only read from our own\n>    output do not have to accommodate CRLF-terminated lines, but they\n>    can be updated to do so safely if we do not rely on the ability\n>    to express a payload that has CR at the end.  For example, the\n>    insn sheet \"rebase -i\" uses typically ends each line with a\n>    commit log summary that we ourselves do not read or use, so even\n>    if the end-user on a platform with LF lines deliberately does\n>    insert \\r at the end of the line and strbuf_gets() removed that\n>    \\r from the payload, no unexpected behaviour should happen.\n> \n>    This series does not touch them, but it may be a good GSoC\n>    microproject to convert them to use strbuf_getline_crlf().\n> \n>  * Callers of strbuf_getline() that call strbuf_trim() immediately\n>    on the result before doing anything, or otherwise have logic that\n>    tolerates whitespaces at the end of the line, can continue using\n>    strbuf_getline() and will not misbehave on CRLF-terminated lines.\n> \n>    This series does not touch them; converting them to use\n>    strbuf_getline_crlf() would a good way to document them as\n>    dealing with \"text\".  While doing so, they can also lose their\n>    custom logic that happens to make CRLF-terminated lines work.\n> \n>  * A caller of strbuf_getline() that wants to only see LF-terminated\n>    lines (in other words, \"ABC\\r\\n\" must be treated as a line with 4\n>    bytes payload on it, A B C and CR), would be broken if we replace\n>    it with strbuf_getline_crlf().  This series does not touch them,\n>    and no follow-up series should, either.\n\nThanks for the detailed explanation. I totally agree that (2) would make\nfor a good micro-project.\n\nWhile I am pretty convinced that strbuf_getline() that retains a CR makes\nno sense, it is obviously the correct thing to prove that rather than\nassume it (after all, some caller might exploit strbuf_getline() for its\nauto-growing capabilities even on a binary stream when it is known that it\ncannot contain a 0x0a).\n\nAnd please accept my gratitude for tackling this project.\n\nCiao,\nDscho\n"},{"id":"275299","messageId":"alpine.DEB.2.20.1601041255110.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-2-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 01/17] strbuf: make strbuf_getline_crlf() global","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:25:35Z","receivedAt":"2016-01-04T12:25:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> Often we read \"text\" files that are supplied by the end user\n> (e.g. commit log message that was edited with $GIT_EDITOR upon\n> 'git commit -e'), and in some environments lines in a text file\n> are terminated with CRLF.  Existing strbuf_getline() knows to read\n> a single line and then strip the terminating byte from the result,\n> but it is handy to have a version that is more tailored for a \"text\"\n> input that takes both '\\n' and '\\r\\n' as line terminator (aka\n> <newline> in POSIX lingo) and returns the body of the line after\n> stripping <newline>.\n> \n> Recently reimplemented \"git am\" uses such a function implemented\n> privately; move it to strbuf.[ch] and make it available for others.\n\n... While at it, we fix the formatting of the strbuf_getline() function.\n\nCiao,\nDscho\n"},{"id":"275300","messageId":"alpine.DEB.2.20.1601041258280.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-3-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 02/17] check-attr, check-ignore, checkout-index: read paths with strbuf_getline_crlf()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:25:43Z","receivedAt":"2016-01-04T12:25:43Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> These commands read list of paths from their standard input under\n> the --stdin option (in order to avoid busting limit on the length of\n> the command line).\n> \n> When they are using text input mode (i.e. line_termination is set to\n> '\\n'), we should try to be more friendly to our DOSsy friends and\n> accept lines with CRLF endings.\n> \n> It is tempting to lift this logic to strbuf_getline() and not introduce\n> a separate strbuf_getline_crlf(), but that can lead to silent\n> misconversion.\n\nThis paragraph would make more sense in 01/17.\n\n> diff --git a/builtin/check-attr.c b/builtin/check-attr.c\n> index 265c9ba..4c44d8f 100644\n> --- a/builtin/check-attr.c\n> +++ b/builtin/check-attr.c\n> @@ -77,7 +77,9 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n>  \n>  \tstrbuf_init(&buf, 0);\n>  \tstrbuf_init(&nbuf, 0);\n> -\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n> +\twhile ((line_termination\n> +\t\t? strbuf_getline_crlf(&buf, stdin)\n> +\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n>  \t\tif (line_termination && buf.buf[0] == '\"') {\n>  \t\t\tstrbuf_reset(&nbuf);\n>  \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n\nHrm. With this much context, it is unclear that line_termination can only\never be '\\n' or '\\0'. In fact, with the intention of this hunk, the\nline_termination variable makes no sense any longer because its value is\nnot even used any longer. So something like this instead (and likewise in\ncheck-ignore.c)?\n\n-- snipsnap --\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 265c9ba..605bbf9 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -73,12 +73,13 @@ static void check_attr_stdin_paths(const char *prefix,\nint cnt,\n \tstruct git_attr_check *check)\n {\n \tstruct strbuf buf, nbuf;\n-\tint line_termination = nul_term_line ? 0 : '\\n';\n \n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n-\t\tif (line_termination && buf.buf[0] == '\"') {\n+\twhile ((nul_term_line\n+\t\t\t? strbuf_getline(&buf, stdin, '\\0')\n+\t\t\t: strbuf_getline_crlf(&buf, stdin)) != EOF) {\n+\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n"},{"id":"275302","messageId":"alpine.DEB.2.20.1601041305020.14434@virtualbox","threadId":"40059","inReplyTo":"alpine.DEB.2.20.1601041258280.14434@virtualbox","subject":"Re: [PATCH v2 02/17] check-attr, check-ignore, checkout-index: read paths with strbuf_getline_crlf()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:27:26Z","receivedAt":"2016-01-04T12:27:26Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Mon, 4 Jan 2016, Johannes Schindelin wrote:\n\n>  \tstrbuf_init(&buf, 0);\n>  \tstrbuf_init(&nbuf, 0);\n> -\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n> -\t\tif (line_termination && buf.buf[0] == '\"') {\n> +\twhile ((nul_term_line\n> +\t\t\t? strbuf_getline(&buf, stdin, '\\0')\n> +\t\t\t: strbuf_getline_crlf(&buf, stdin)) != EOF) {\n> +\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n>  \t\t\tstrbuf_reset(&nbuf);\n>  \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n\nFWIW this is an example of that \"abuse\" I referred to earlier: the call to\nstrbuf_getline(..., '\\0') is actually *not* interested in a line at all.\nSo I guess I would suggest to change the name \"strbuf_getline\" to\n\"strbuf_getdelim\" first, and then re-introduce a different\n\"strbuf_getline\" which is actually your \"strbuf_getline_crlf\". Because\nlet's face it, if we are really reading a line of text, CR/LF should be\nhandled automatically.\n\nCiao,\nDscho\n"},{"id":"275303","messageId":"alpine.DEB.2.20.1601041308310.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-4-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 03/17] update-index: read --index-info with strbuf_getline_crlf()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:27:31Z","receivedAt":"2016-01-04T12:27:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> diff --git a/builtin/update-index.c b/builtin/update-index.c\n> index 7431938..a7a9a7e 100644\n> --- a/builtin/update-index.c\n> +++ b/builtin/update-index.c\n> @@ -473,7 +473,9 @@ static void read_index_info(int line_termination)\n>  \tstruct strbuf buf = STRBUF_INIT;\n>  \tstruct strbuf uq = STRBUF_INIT;\n>  \n> -\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n> +\twhile ((line_termination\n> +\t\t? strbuf_getline_crlf(&buf, stdin)\n> +\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n>  \t\tchar *ptr, *tab;\n\nThis is a problematic change because it does not safeguard for future\nintroduction of a line_termination value other than LF or NUL. I believe\nthe safest would be to change read_index_info() to take a `nul_delimited`\nparameter instead of the `line_termination` parameter first, and then\nintroduce that change to use strbuf_getline_crlf if !nul_delimited.\n\nCiao,\nDscho\n"},{"id":"275304","messageId":"alpine.DEB.2.20.1601041314240.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-5-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 04/17] update-index: read list of paths with strbuf_getline_crlf() under --stdin","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:27:36Z","receivedAt":"2016-01-04T12:27:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> diff --git a/builtin/update-index.c b/builtin/update-index.c\n> index a7a9a7e..3a6c5b2 100644\n> --- a/builtin/update-index.c\n> +++ b/builtin/update-index.c\n> @@ -1075,7 +1075,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n>  \t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n>  \n>  \t\tsetup_work_tree();\n> -\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n> +\n> +\t\twhile ((line_termination\n> +\t\t\t? strbuf_getline_crlf(&buf, stdin)\n> +\t\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n>  \t\t\tchar *p;\n>  \t\t\tif (line_termination && buf.buf[0] == '\"') {\n\nAgain, I think it would make things clearer and more future proof if we\nchanged the logic to talk about nul_delimited instead of line_termination.\n\nCiao,\nDscho\n"},{"id":"275305","messageId":"alpine.DEB.2.20.1601041316370.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 05/17] mktree: read textual tree representation with strbuf_getline_crlf()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:27:41Z","receivedAt":"2016-01-04T12:27:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> diff --git a/builtin/mktree.c b/builtin/mktree.c\n> index a964d6b..c6cafb6 100644\n> --- a/builtin/mktree.c\n> +++ b/builtin/mktree.c\n> @@ -157,7 +157,9 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n>  \n>  \twhile (!got_eof) {\n>  \t\twhile (1) {\n> -\t\t\tif (strbuf_getline(&sb, stdin, line_termination) == EOF) {\n> +\t\t\tif ((line_termination\n> +\t\t\t     ? strbuf_getline_crlf(&sb, stdin)\n> +\t\t\t     : strbuf_getline(&sb, stdin, '\\0')) == EOF) {\n>  \t\t\t\tgot_eof = 1;\n>  \t\t\t\tbreak;\n>  \t\t\t}\n\nHere also, I would recommend to change the logic to talk about\nnul_delimited instead of line_termination first, and only then introduce\nthe change to call two different strbuf_* functions.\n\nCiao,\nDscho\n"},{"id":"275301","messageId":"alpine.DEB.2.20.1601041321360.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-17-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 16/17] grep: read -f file with strbuf_getline_crlf()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:27:44Z","receivedAt":"2016-01-04T12:27:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 16 Dec 2015, Junio C Hamano wrote:\n\n> This is iffy; you may actually be trying to find a line with ^M in\n> it on a system whose line ending is LF.  You can of course work it\n> around by having a line that has \"^M^M^J\", let the strbuf_getline_crlf() eat\n> the last \"^M^J\", leaving just the single \"^M\" as the pattern.\n\nThanks for being careful.\n\nHaving said that, `grep` operates on lines of text, and CR is established\nas a non-text byte, so I would argue that the previous behavior was\nactually incorrect: if you searched for, say, `abc$` in a CR/LF delimited\nfile, the outcome would not have met my expectation of correct behavior.\n\nCiao,\nDscho\n"},{"id":"275306","messageId":"alpine.DEB.2.20.1601041323550.14434@virtualbox","threadId":"40059","inReplyTo":"1450303398-25900-18-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 17/17] test-sha1-array: read command stream with strbuf_getline_crlf()","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2016-01-04T12:27:49Z","receivedAt":"2016-01-04T12:27:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nI read through the entire series. I hope you find my comments helpful.\n\nHappy new year,\nDscho\n"},{"id":"275317","messageId":"xmqqvb79nogx.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"alpine.DEB.2.20.1601041255110.14434@virtualbox","subject":"Re: [PATCH v2 01/17] strbuf: make strbuf_getline_crlf() global","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-04T19:17:50Z","receivedAt":"2016-01-04T19:17:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Junio,\n>\n> On Wed, 16 Dec 2015, Junio C Hamano wrote:\n>\n>> Often we read \"text\" files that are supplied by the end user\n>> (e.g. commit log message that was edited with $GIT_EDITOR upon\n>> 'git commit -e'), and in some environments lines in a text file\n>> are terminated with CRLF.  Existing strbuf_getline() knows to read\n>> a single line and then strip the terminating byte from the result,\n>> but it is handy to have a version that is more tailored for a \"text\"\n>> input that takes both '\\n' and '\\r\\n' as line terminator (aka\n>> <newline> in POSIX lingo) and returns the body of the line after\n>> stripping <newline>.\n>> \n>> Recently reimplemented \"git am\" uses such a function implemented\n>> privately; move it to strbuf.[ch] and make it available for others.\n>\n> ... While at it, we fix the formatting of the strbuf_getline() function.\n\nYeah right; I think it is obvious from the patch text, but while at\nit, I'll amend the log message ;-)\n\nThanks.\n"},{"id":"275318","messageId":"xmqqr3hxnobv.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"alpine.DEB.2.20.1601041305020.14434@virtualbox","subject":"Re: [PATCH v2 02/17] check-attr, check-ignore, checkout-index: read paths with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-04T19:20:52Z","receivedAt":"2016-01-04T19:20:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> So I guess I would suggest to change the name \"strbuf_getline\" to\n> \"strbuf_getdelim\" first, and then re-introduce a different\n> \"strbuf_getline\" which is actually your \"strbuf_getline_crlf\".\n\nMakes sense.  I really hated that name \"getline_crlf\".\n"},{"id":"275319","messageId":"xmqqmvslnnvb.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"alpine.DEB.2.20.1601041321360.14434@virtualbox","subject":"Re: [PATCH v2 16/17] grep: read -f file with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-04T19:30:48Z","receivedAt":"2016-01-04T19:30:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Having said that, `grep` operates on lines of text,\n\nCorrect.\n\n> and CR is established as a non-text byte,\n\nCorrect but only if you are a pedant.\n\nWith this patch, you can no longer find \"A<CR>\" on a \"line\" that is\n\"A<CR><LF>\", which is a regression on a system whose native line\nermination convention is to use a single LF at the end.\n\nThe thing is, users know \"grep -e '<a non-text byte>' finds hits\nwith a line with the non-text byte, and telling them that they\nshouldn't rely on the feature would not make the world a better\nplace.\n\nThis patch limits the damage by restricting the special casing of CR\nonly at the end of the line just before LF, so we can still find\n\"A<CR>B\" on a \"line\" that has a non-text byte, e.g. \"A<CR>B<CR><LF>\"\nor \"A<CR>B<LF>\".  It is just a <CR> at the end of the line (with or\nwithout any other string before it) for which we see a regression,\nand I suspect that it would be a small enough price to accept to\nhelp those who would need to work with <CRLF> systems.\n"},{"id":"275320","messageId":"xmqqio39nmye.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"alpine.DEB.2.20.1601041308310.14434@virtualbox","subject":"Re: [PATCH v2 03/17] update-index: read --index-info with strbuf_getline_crlf()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-04T19:50:33Z","receivedAt":"2016-01-04T19:50:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> diff --git a/builtin/update-index.c b/builtin/update-index.c\n>> index 7431938..a7a9a7e 100644\n>> --- a/builtin/update-index.c\n>> +++ b/builtin/update-index.c\n>> @@ -473,7 +473,9 @@ static void read_index_info(int line_termination)\n>>  \tstruct strbuf buf = STRBUF_INIT;\n>>  \tstruct strbuf uq = STRBUF_INIT;\n>>  \n>> -\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n>> +\twhile ((line_termination\n>> +\t\t? strbuf_getline_crlf(&buf, stdin)\n>> +\t\t: strbuf_getline(&buf, stdin, '\\0')) != EOF) {\n>>  \t\tchar *ptr, *tab;\n>\n> This is a problematic change because it does not safeguard for future\n> introduction of a line_termination value other than LF or NUL. I believe\n> the safest would be to change read_index_info() to take a `nul_delimited`\n> parameter instead of the `line_termination` parameter first, and then\n> introduce that change to use strbuf_getline_crlf if !nul_delimited.\n\nWhen I introduced line_termination long time ago, I wrote these\ncodepaths anticipating that there might be a value other than NUL\nand LF that could be useful, but no useful caller that uses other\nuseful value has emerged, so I agree that the interface was too\nbroad and general for its own good.\n\nI agree with your comments for all the changes in this series that\nswitch between getline and getline_delim('\\0') based on the value of\nline_termination; its generality is useless and we should declare\n\"the line termination is either NUL or LF, no other choices\"; using\nnul_delimited = 0/1 is a very good way to express it clearly.\n\nThanks.\n"},{"id":"275990","messageId":"1452740590-16827-1-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1450303398-25900-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 0/9] Preview of \"Peace with CRLF\" rerolled","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:00Z","receivedAt":"2016-01-14T03:03:00Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Continued from\n\n http://thread.gmane.org/gmane.comp.version-control.git/282614\n\nHere is only the preparatory part that\n\n - introduces strbuf_getline_lf() and strbuf_getine_nul() and\n   converts existing callers to strbut_getline() to use them;\n\n - retires strbuf_getline() that takes an arbitrary line terminator\n   and demotes it to strbuf_getdelim() that is merely an\n   implementation detail inside strbuf.c; and\n\n - gives the short-and-sweet name strbuf_getline() to the most\n   \"text friendly\" strbuf_getline_crlf().\n\nI am sending this out as preview now before implementing the main\npart of the series that audits callers of strbuf_getline_lf() and\nselectively turns them into strbuf_getline().  The work I did for v2\nthat corresponds to that main part will have to be redone because of\nthe changes to function names made by these preparatory steps, and\nit would be rather boring mechanical and time-consuming work that is\nprone to stupid mistakes, which I do not want to start late in the\nday.\n\nJunio C Hamano (9):\n  strbuf: miniscule style fix\n  strbuf: make strbuf_getline_crlf() global\n  strbuf: introduce strbuf_getline_{lf,nul}()\n  mktree: there are only two line terminators\n  check-attr: there are only two line terminators\n  check-ignore: there are only two line terminators\n  update-index: there are only two line terminators\n  checkout-index: there are only two line terminators\n  strbuf: give strbuf_getline() to the \"most text friendly\" variant\n\n bisect.c                   |  8 ++++----\n builtin/am.c               | 37 +++++++++++--------------------------\n builtin/cat-file.c         |  2 +-\n builtin/check-attr.c       |  7 ++++---\n builtin/check-ignore.c     |  7 ++++---\n builtin/check-mailmap.c    |  2 +-\n builtin/checkout-index.c   | 10 +++++++---\n builtin/clean.c            |  6 +++---\n builtin/clone.c            |  2 +-\n builtin/column.c           |  2 +-\n builtin/commit.c           |  2 +-\n builtin/fetch-pack.c       |  2 +-\n builtin/grep.c             |  2 +-\n builtin/hash-object.c      |  2 +-\n builtin/mailinfo.c         |  8 ++++----\n builtin/mktree.c           | 14 ++++++++------\n builtin/notes.c            |  2 +-\n builtin/pull.c             |  2 +-\n builtin/repack.c           |  2 +-\n builtin/rev-parse.c        |  4 ++--\n builtin/send-pack.c        |  2 +-\n builtin/update-index.c     | 27 ++++++++++++++++-----------\n compat/terminal.c          |  2 +-\n credential-cache--daemon.c |  4 ++--\n credential-store.c         |  2 +-\n credential.c               |  2 +-\n daemon.c                   |  2 +-\n fast-import.c              |  4 ++--\n ident.c                    |  2 +-\n remote-curl.c              |  6 +++---\n remote-testsvn.c           |  4 ++--\n remote.c                   |  4 ++--\n sequencer.c                |  2 +-\n sha1_file.c                |  2 +-\n shell.c                    |  2 +-\n strbuf.c                   | 28 +++++++++++++++++++++++++---\n strbuf.h                   | 27 ++++++++++++++++++++++-----\n test-sha1-array.c          |  2 +-\n transport-helper.c         |  5 +++--\n walker.c                   |  2 +-\n wt-status.c                |  4 ++--\n 41 files changed, 148 insertions(+), 110 deletions(-)\n\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275992","messageId":"1452740590-16827-2-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 1/9] strbuf: miniscule style fix","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:01Z","receivedAt":"2016-01-14T03:03:01Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We write one SP on each side of an operator, even inside an [] pair\nthat computes the array index.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n strbuf.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex d76f0ae..b165d04 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -505,8 +505,8 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n-\tif (sb->buf[sb->len-1] == term)\n-\t\tstrbuf_setlen(sb, sb->len-1);\n+\tif (sb->buf[sb->len - 1] == term)\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n \treturn 0;\n }\n \n-- \n2.7.0-242-gdd583c7\n"},{"id":"275991","messageId":"1452740590-16827-3-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 2/9] strbuf: make strbuf_getline_crlf() global","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:02Z","receivedAt":"2016-01-14T03:03:02Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Often we read \"text\" files that are supplied by the end user\n(e.g. commit log message that was edited with $GIT_EDITOR upon 'git\ncommit -e'), and in some environments lines in a text file are\nterminated with CRLF.  Existing strbuf_getline() knows to read a\nsingle line and then strip the terminating byte from the result, but\nit is handy to have a version that is more tailored for a \"text\"\ninput that takes both '\\n' and '\\r\\n' as line terminator (aka\n<newline> in POSIX lingo) and returns the body of the line after\nstripping <newline>.\n\nRecently reimplemented \"git am\" uses such a function implemented\nprivately; move it to strbuf.[ch] and make it available for others.\n\nNote that we do not blindly replace calls to strbuf_getline() that\nuses LF as the line terminator with calls to strbuf_getline_crlf()\nand this is very much deliberate.  Some callers may want to treat an\nincoming line that ends with CR (and terminated with LF) to have a\npayload that includes the final CR, and such a blind replacement\nwill result in misconversion when done without code audit.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 15 ---------------\n strbuf.c     | 12 ++++++++++++\n strbuf.h     |  7 +++++++\n 3 files changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 4e396c8..94a533a 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -45,21 +45,6 @@ static int is_empty_file(const char *filename)\n }\n \n /**\n- * Like strbuf_getline(), but treats both '\\n' and \"\\r\\n\" as line terminators.\n- */\n-static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n-{\n-\tif (strbuf_getwholeline(sb, fp, '\\n'))\n-\t\treturn EOF;\n-\tif (sb->buf[sb->len - 1] == '\\n') {\n-\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t\tif (sb->len > 0 && sb->buf[sb->len - 1] == '\\r')\n-\t\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n  * Returns the length of the first line of msg.\n  */\n static int linelen(const char *msg)\ndiff --git a/strbuf.c b/strbuf.c\nindex b165d04..7ad5ea4 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -510,6 +510,18 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n \treturn 0;\n }\n \n+int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n+{\n+\tif (strbuf_getwholeline(sb, fp, '\\n'))\n+\t\treturn EOF;\n+\tif (sb->buf[sb->len - 1] == '\\n') {\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t\tif (sb->len && sb->buf[sb->len - 1] == '\\r')\n+\t\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t}\n+\treturn 0;\n+}\n+\n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\n {\n \tstrbuf_reset(sb);\ndiff --git a/strbuf.h b/strbuf.h\nindex 7123fca..d84c866 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -388,6 +388,13 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  */\n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+/*\n+ * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n+ * and additionally treats a '\\r' that comes immediately before '\\n'\n+ * as part of the terminator.\n+ */\n+extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n+\n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\n  * any) in the buffer.\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275993","messageId":"1452740590-16827-4-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 3/9] strbuf: introduce strbuf_getline_{lf,nul}()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:03Z","receivedAt":"2016-01-14T03:03:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The strbuf_getline() interface allows a byte other than LF or NUL as\nthe line terminator, but this is only because I wrote these\ncodepaths anticipating that there might be a value other than NUL\nand LF that could be useful when I introduced line_termination long\ntime ago.  No useful caller that uses other value has emerged.\n\nBy now, it is clear that the interface is overly broad without a\ngood reason.  Many codepaths have hardcoded preference to read\neither LF terminated or NUL terminated records from their input, and\nthen call strbuf_getline() with LF or NUL as the third parameter.\n\nThis step introduces two thin wrappers around strbuf_getline(),\nnamely, strbuf_getline_lf() and strbuf_getline_nul(), and\nmechanically rewrites these call sites to call either one of\nthem.  The changes contained in this patch are:\n\n * introduction of these two functions in strbuf.[ch]\n\n * mechanical conversion of all callers to strbuf_getline() with\n   either '\\n' or '\\0' as the third parameter to instead call the\n   respective thin wrapper.\n\nAfter this step, output from \"git grep 'strbuf_getline('\" would\nbecome a lot smaller.  An interim goal of this series is to make\nthis an empty set, so that we can have strbuf_getline_crlf() take\nover the shorter name strbuf_getline().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n bisect.c                   |  8 ++++----\n builtin/am.c               | 14 +++++++-------\n builtin/cat-file.c         |  2 +-\n builtin/check-mailmap.c    |  2 +-\n builtin/clean.c            |  6 +++---\n builtin/clone.c            |  2 +-\n builtin/column.c           |  2 +-\n builtin/commit.c           |  2 +-\n builtin/fetch-pack.c       |  2 +-\n builtin/grep.c             |  2 +-\n builtin/hash-object.c      |  2 +-\n builtin/mailinfo.c         |  8 ++++----\n builtin/notes.c            |  2 +-\n builtin/pull.c             |  2 +-\n builtin/repack.c           |  2 +-\n builtin/rev-parse.c        |  4 ++--\n builtin/send-pack.c        |  2 +-\n compat/terminal.c          |  2 +-\n credential-cache--daemon.c |  4 ++--\n credential-store.c         |  2 +-\n credential.c               |  2 +-\n daemon.c                   |  2 +-\n fast-import.c              |  4 ++--\n ident.c                    |  2 +-\n remote-curl.c              |  6 +++---\n remote-testsvn.c           |  4 ++--\n remote.c                   |  4 ++--\n sequencer.c                |  2 +-\n sha1_file.c                |  2 +-\n shell.c                    |  2 +-\n strbuf.c                   | 10 ++++++++++\n strbuf.h                   |  7 +++++++\n test-sha1-array.c          |  2 +-\n transport-helper.c         |  2 +-\n walker.c                   |  2 +-\n wt-status.c                |  4 ++--\n 36 files changed, 73 insertions(+), 56 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 053d1a2..4bbf93e 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -440,7 +440,7 @@ static void read_bisect_paths(struct argv_array *array)\n \tif (!fp)\n \t\tdie_errno(\"Could not open file '%s'\", filename);\n \n-\twhile (strbuf_getline(&str, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&str, fp) != EOF) {\n \t\tstrbuf_trim(&str);\n \t\tif (sq_dequote_to_argv_array(str.buf, array))\n \t\t\tdie(\"Badly quoted content in file '%s': %s\",\n@@ -668,7 +668,7 @@ static int is_expected_rev(const struct object_id *oid)\n \tif (!fp)\n \t\treturn 0;\n \n-\tif (strbuf_getline(&str, fp, '\\n') != EOF)\n+\tif (strbuf_getline_lf(&str, fp) != EOF)\n \t\tres = !strcmp(str.buf, oid_to_hex(oid));\n \n \tstrbuf_release(&str);\n@@ -914,9 +914,9 @@ void read_bisect_terms(const char **read_bad, const char **read_good)\n \t\t\t\tstrerror(errno));\n \t\t}\n \t} else {\n-\t\tstrbuf_getline(&str, fp, '\\n');\n+\t\tstrbuf_getline_lf(&str, fp);\n \t\t*read_bad = strbuf_detach(&str, NULL);\n-\t\tstrbuf_getline(&str, fp, '\\n');\n+\t\tstrbuf_getline_lf(&str, fp);\n \t\t*read_good = strbuf_detach(&str, NULL);\n \t}\n \tstrbuf_release(&str);\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 94a533a..885fa19 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -268,7 +268,7 @@ static char *read_shell_var(FILE *fp, const char *key)\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *str;\n \n-\tif (strbuf_getline(&sb, fp, '\\n'))\n+\tif (strbuf_getline_lf(&sb, fp))\n \t\tgoto fail;\n \n \tif (!skip_prefix(sb.buf, key, &str))\n@@ -557,7 +557,7 @@ static int copy_notes_for_rebase(const struct am_state *state)\n \n \tfp = xfopen(am_path(state, \"rewritten\"), \"r\");\n \n-\twhile (!strbuf_getline(&sb, fp, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, fp)) {\n \t\tunsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];\n \n \t\tif (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {\n@@ -801,7 +801,7 @@ static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \tstruct strbuf sb = STRBUF_INIT;\n \tint subject_printed = 0;\n \n-\twhile (!strbuf_getline(&sb, in, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, in)) {\n \t\tconst char *str;\n \n \t\tif (str_isspace(sb.buf))\n@@ -859,7 +859,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,\n \t\treturn error(_(\"could not open '%s' for reading: %s\"), *paths,\n \t\t\t\tstrerror(errno));\n \n-\twhile (!strbuf_getline(&sb, fp, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, fp)) {\n \t\tif (*sb.buf == '#')\n \t\t\tcontinue; /* skip comment lines */\n \n@@ -884,7 +884,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\twhile (!strbuf_getline(&sb, in, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, in)) {\n \t\tconst char *str;\n \n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n@@ -1298,7 +1298,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \t/* Extract message and author information */\n \tfp = xfopen(am_path(state, \"info\"), \"r\");\n-\twhile (!strbuf_getline(&sb, fp, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, fp)) {\n \t\tconst char *x;\n \n \t\tif (skip_prefix(sb.buf, \"Subject: \", &x)) {\n@@ -1364,7 +1364,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)\n \tFILE *fp = xfopen(mail, \"r\");\n \tconst char *x;\n \n-\tif (strbuf_getline(&sb, fp, '\\n'))\n+\tif (strbuf_getline_lf(&sb, fp))\n \t\treturn -1;\n \n \tif (!skip_prefix(sb.buf, \"From \", &x))\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex c0fd8db..d2ebaf1 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n \tsave_warning = warn_on_object_refname_ambiguity;\n \twarn_on_object_refname_ambiguity = 0;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\tif (data.split_on_whitespace) {\n \t\t\t/*\n \t\t\t * Split at first whitespace, tying off the beginning\ndiff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c\nindex eaaea54..cf0f54f 100644\n--- a/builtin/check-mailmap.c\n+++ b/builtin/check-mailmap.c\n@@ -54,7 +54,7 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)\n \n \tif (use_stdin) {\n \t\tstruct strbuf buf = STRBUF_INIT;\n-\t\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\t\tcheck_mailmap(&mailmap, buf.buf);\n \t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n \t\t}\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex d7acb94..cc5f972 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -594,7 +594,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t       clean_get_color(CLEAN_COLOR_RESET));\n \t\t}\n \n-\t\tif (strbuf_getline(&choice, stdin, '\\n') != EOF) {\n+\t\tif (strbuf_getline_lf(&choice, stdin) != EOF) {\n \t\t\tstrbuf_trim(&choice);\n \t\t} else {\n \t\t\teof = 1;\n@@ -676,7 +676,7 @@ static int filter_by_patterns_cmd(void)\n \t\tclean_print_color(CLEAN_COLOR_PROMPT);\n \t\tprintf(_(\"Input ignore patterns>> \"));\n \t\tclean_print_color(CLEAN_COLOR_RESET);\n-\t\tif (strbuf_getline(&confirm, stdin, '\\n') != EOF)\n+\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF)\n \t\t\tstrbuf_trim(&confirm);\n \t\telse\n \t\t\tputchar('\\n');\n@@ -774,7 +774,7 @@ static int ask_each_cmd(void)\n \t\t\tqname = quote_path_relative(item->string, NULL, &buf);\n \t\t\t/* TRANSLATORS: Make sure to keep [y/N] as is */\n \t\t\tprintf(_(\"Remove %s [y/N]? \"), qname);\n-\t\t\tif (strbuf_getline(&confirm, stdin, '\\n') != EOF) {\n+\t\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF) {\n \t\t\t\tstrbuf_trim(&confirm);\n \t\t\t} else {\n \t\t\t\tputchar('\\n');\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 9eaecd9..182af32 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n \tFILE *in = fopen(src->buf, \"r\");\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, in) != EOF) {\n \t\tchar *abs_path;\n \t\tif (!line.len || line.buf[0] == '#')\n \t\t\tcontinue;\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 449413c..40eab08 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--command must be the first argument\"));\n \t}\n \tfinalize_colopts(&colopts, -1);\n-\twhile (!strbuf_getline(&sb, stdin, '\\n'))\n+\twhile (!strbuf_getline_lf(&sb, stdin))\n \t\tstring_list_append(&list, sb.buf);\n \n \tprint_columns(&list, colopts, &copts);\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex dca09e2..fe247ed 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1687,7 +1687,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tif (fp == NULL)\n \t\t\tdie_errno(_(\"could not open '%s' for reading\"),\n \t\t\t\t  git_path_merge_head());\n-\t\twhile (strbuf_getline(&m, fp, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&m, fp) != EOF) {\n \t\t\tstruct commit *parent;\n \n \t\t\tparent = get_merge_parent(m.buf);\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex 4a6b340..e6cc151 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -156,7 +156,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\telse {\n \t\t\t/* read from stdin one ref per line, until EOF */\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline(&line, stdin, '\\n') != EOF)\n+\t\t\twhile (strbuf_getline_lf(&line, stdin) != EOF)\n \t\t\t\tadd_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex d04f440..b2346f1 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -562,7 +562,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n-\twhile (strbuf_getline(&sb, patterns, '\\n') == 0) {\n+\twhile (strbuf_getline_lf(&sb, patterns) == 0) {\n \t\t/* ignore empty line like grep does */\n \t\tif (sb.len == 0)\n \t\t\tcontinue;\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 43b098b..3bc5ec1 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n {\n \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/mailinfo.c b/builtin/mailinfo.c\nindex 999a525..694c357 100644\n--- a/builtin/mailinfo.c\n+++ b/builtin/mailinfo.c\n@@ -410,7 +410,7 @@ static int is_rfc2822_header(const struct strbuf *line)\n static int read_one_header_line(struct strbuf *line, FILE *in)\n {\n \t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n+\tif (strbuf_getline_lf(line, in))\n \t\treturn 0;\n \n \t/*\n@@ -435,7 +435,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in)\n \t\tpeek = fgetc(in); ungetc(peek, in);\n \t\tif (peek != ' ' && peek != '\\t')\n \t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n+\t\tif (strbuf_getline_lf(&continuation, in))\n \t\t\tbreak;\n \t\tcontinuation.buf[0] = ' ';\n \t\tstrbuf_rtrim(&continuation);\n@@ -644,7 +644,7 @@ static void handle_filter(struct strbuf *line);\n \n static int find_boundary(void)\n {\n-\twhile (!strbuf_getline(&line, fin, '\\n')) {\n+\twhile (!strbuf_getline_lf(&line, fin)) {\n \t\tif (*content_top && is_multipart_boundary(&line))\n \t\t\treturn 1;\n \t}\n@@ -692,7 +692,7 @@ again:\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(&line, fin, '\\n'))\n+\tif (strbuf_getline_lf(&line, fin))\n \t\treturn 0;\n \tstrbuf_addch(&line, '\\n');\n \treturn 1;\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 515cebb..c1ace5a 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -290,7 +290,7 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)\n \t\tt = &default_notes_tree;\n \t}\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\tunsigned char from_obj[20], to_obj[20];\n \t\tstruct strbuf **split;\n \t\tint err;\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex bf3fd3f..bdc62ab 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -378,7 +378,7 @@ static void get_merge_heads(struct sha1_array *merge_heads)\n \n \tif (!(fp = fopen(filename, \"r\")))\n \t\tdie_errno(_(\"could not open '%s' for reading\"), filename);\n-\twhile (strbuf_getline(&sb, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&sb, fp) != EOF) {\n \t\tif (get_sha1_hex(sb.buf, sha1))\n \t\t\tcontinue;  /* invalid line: does not start with SHA1 */\n \t\tif (starts_with(sb.buf + GIT_SHA1_HEXSZ, \"\\tnot-for-merge\\t\"))\ndiff --git a/builtin/repack.c b/builtin/repack.c\nindex 9456110..858db38 100644\n--- a/builtin/repack.c\n+++ b/builtin/repack.c\n@@ -266,7 +266,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)\n \t\treturn ret;\n \n \tout = xfdopen(cmd.out, \"r\");\n-\twhile (strbuf_getline(&line, out, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, out) != EOF) {\n \t\tif (line.len != 40)\n \t\t\tdie(\"repack: Expecting 40 character sha1 lines only from pack-objects.\");\n \t\tstring_list_append(&names, line.buf);\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 02d747d..b827ffd 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -386,7 +386,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \n \t/* get the usage up to the first line with a -- on it */\n \tfor (;;) {\n-\t\tif (strbuf_getline(&sb, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(&sb, stdin) == EOF)\n \t\t\tdie(\"premature end of input\");\n \t\tALLOC_GROW(usage, unb + 1, usz);\n \t\tif (!strcmp(\"--\", sb.buf)) {\n@@ -399,7 +399,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&sb, stdin) != EOF) {\n \t\tconst char *s;\n \t\tconst char *help;\n \t\tstruct option *o;\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex f6e5d64..8f9f4f1 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targv_array_push(&all_refspecs, buf);\n \t\t} else {\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline(&line, stdin, '\\n') != EOF)\n+\t\t\twhile (strbuf_getline_lf(&line, stdin) != EOF)\n \t\t\t\targv_array_push(&all_refspecs, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\ndiff --git a/compat/terminal.c b/compat/terminal.c\nindex 313897d..fa13ee6 100644\n--- a/compat/terminal.c\n+++ b/compat/terminal.c\n@@ -122,7 +122,7 @@ char *git_terminal_prompt(const char *prompt, int echo)\n \tfputs(prompt, output_fh);\n \tfflush(output_fh);\n \n-\tr = strbuf_getline(&buf, input_fh, '\\n');\n+\tr = strbuf_getline_lf(&buf, input_fh);\n \tif (!echo) {\n \t\tputc('\\n', output_fh);\n \t\tfflush(output_fh);\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex eef6fce..3db5d68 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -97,12 +97,12 @@ static int read_request(FILE *fh, struct credential *c,\n \tstatic struct strbuf item = STRBUF_INIT;\n \tconst char *p;\n \n-\tstrbuf_getline(&item, fh, '\\n');\n+\tstrbuf_getline_lf(&item, fh);\n \tif (!skip_prefix(item.buf, \"action=\", &p))\n \t\treturn error(\"client sent bogus action line: %s\", item.buf);\n \tstrbuf_addstr(action, p);\n \n-\tstrbuf_getline(&item, fh, '\\n');\n+\tstrbuf_getline_lf(&item, fh);\n \tif (!skip_prefix(item.buf, \"timeout=\", &p))\n \t\treturn error(\"client sent bogus timeout line: %s\", item.buf);\n \t*timeout = atoi(p);\ndiff --git a/credential-store.c b/credential-store.c\nindex 00aea3a..c5f9a0e 100644\n--- a/credential-store.c\n+++ b/credential-store.c\n@@ -23,7 +23,7 @@ static int parse_credential_file(const char *fn,\n \t\treturn found_credential;\n \t}\n \n-\twhile (strbuf_getline(&line, fh, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, fh) != EOF) {\n \t\tcredential_from_url(&entry, line.buf);\n \t\tif (entry.username && entry.password &&\n \t\t    credential_match(c, &entry)) {\ndiff --git a/credential.c b/credential.c\nindex b146ad8..7d6501d 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -142,7 +142,7 @@ int credential_read(struct credential *c, FILE *fp)\n {\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, fp) != EOF) {\n \t\tchar *key = line.buf;\n \t\tchar *value = strchr(key, '=');\n \ndiff --git a/daemon.c b/daemon.c\nindex 56679a1..161c0cf 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -424,7 +424,7 @@ static void copy_to_log(int fd)\n \t\treturn;\n \t}\n \n-\twhile (strbuf_getline(&line, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, fp) != EOF) {\n \t\tlogerror(\"%s\", line.buf);\n \t\tstrbuf_setlen(&line, 0);\n \t}\ndiff --git a/fast-import.c b/fast-import.c\nindex e3b421d..ae3ecf0 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1888,7 +1888,7 @@ static int read_next_command(void)\n \t\t\tstruct recent_command *rc;\n \n \t\t\tstrbuf_detach(&command_buf, NULL);\n-\t\t\tstdin_eof = strbuf_getline(&command_buf, stdin, '\\n');\n+\t\t\tstdin_eof = strbuf_getline_lf(&command_buf, stdin);\n \t\t\tif (stdin_eof)\n \t\t\t\treturn EOF;\n \n@@ -1960,7 +1960,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)\n \n \t\tstrbuf_detach(&command_buf, NULL);\n \t\tfor (;;) {\n-\t\t\tif (strbuf_getline(&command_buf, stdin, '\\n') == EOF)\n+\t\t\tif (strbuf_getline_lf(&command_buf, stdin) == EOF)\n \t\t\t\tdie(\"EOF in data (terminator '%s' not found)\", term);\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\ndiff --git a/ident.c b/ident.c\nindex 5ff1aad..9c0b387 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -55,7 +55,7 @@ static int add_mailname_host(struct strbuf *buf)\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\tif (strbuf_getline(&mailnamebuf, mailname, '\\n') == EOF) {\n+\tif (strbuf_getline_lf(&mailnamebuf, mailname) == EOF) {\n \t\tif (ferror(mailname))\n \t\t\twarning(\"cannot read /etc/mailname: %s\",\n \t\t\t\tstrerror(errno));\ndiff --git a/remote-curl.c b/remote-curl.c\nindex cc7a8a6..fcb0004 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -827,7 +827,7 @@ static void parse_fetch(struct strbuf *buf)\n \t\t\tdie(\"http transport does not support %s\", buf->buf);\n \n \t\tstrbuf_reset(buf);\n-\t\tif (strbuf_getline(buf, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(buf, stdin) == EOF)\n \t\t\treturn;\n \t\tif (!*buf->buf)\n \t\t\tbreak;\n@@ -940,7 +940,7 @@ static void parse_push(struct strbuf *buf)\n \t\t\tdie(\"http transport does not support %s\", buf->buf);\n \n \t\tstrbuf_reset(buf);\n-\t\tif (strbuf_getline(buf, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(buf, stdin) == EOF)\n \t\t\tgoto free_specs;\n \t\tif (!*buf->buf)\n \t\t\tbreak;\n@@ -990,7 +990,7 @@ int main(int argc, const char **argv)\n \tdo {\n \t\tconst char *arg;\n \n-\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF) {\n+\t\tif (strbuf_getline_lf(&buf, stdin) == EOF) {\n \t\t\tif (ferror(stdin))\n \t\t\t\terror(\"remote-curl: error reading command stream from git\");\n \t\t\treturn 1;\ndiff --git a/remote-testsvn.c b/remote-testsvn.c\nindex f599c37..f05ff45 100644\n--- a/remote-testsvn.c\n+++ b/remote-testsvn.c\n@@ -154,7 +154,7 @@ static void check_or_regenerate_marks(int latestrev)\n \t\tfclose(marksfile);\n \t} else {\n \t\tstrbuf_addf(&sb, \":%d \", latestrev);\n-\t\twhile (strbuf_getline(&line, marksfile, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&line, marksfile) != EOF) {\n \t\t\tif (starts_with(line.buf, sb.buf)) {\n \t\t\t\tfound++;\n \t\t\t\tbreak;\n@@ -322,7 +322,7 @@ int main(int argc, char **argv)\n \tmarksfilename = marksfilename_sb.buf;\n \n \twhile (1) {\n-\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF) {\n+\t\tif (strbuf_getline_lf(&buf, stdin) == EOF) {\n \t\t\tif (ferror(stdin))\n \t\t\t\tdie(\"Error reading command stream\");\n \t\t\telse\ndiff --git a/remote.c b/remote.c\nindex 1101f82..7e6e625 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \tremote->origin = REMOTE_REMOTES;\n-\twhile (strbuf_getline(&buf, f, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, f) != EOF) {\n \t\tconst char *v;\n \n \t\tstrbuf_rtrim(&buf);\n@@ -281,7 +281,7 @@ static void read_branches_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \n-\tstrbuf_getline(&buf, f, '\\n');\n+\tstrbuf_getline_lf(&buf, f);\n \tstrbuf_trim(&buf);\n \tif (!buf.len) {\n \t\tstrbuf_release(&buf);\ndiff --git a/sequencer.c b/sequencer.c\nindex a0600ae..f1cf735 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -886,7 +886,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \tif (!f)\n \t\treturn error(_(\"cannot open %s: %s\"), git_path_head_file(),\n \t\t\t\t\t\tstrerror(errno));\n-\tif (strbuf_getline(&buf, f, '\\n')) {\n+\tif (strbuf_getline_lf(&buf, f)) {\n \t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n \t\tfclose(f);\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 50896ff..3b66742 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -395,7 +395,7 @@ void add_to_alternates_file(const char *reference)\n \t\tstruct strbuf line = STRBUF_INIT;\n \t\tint found = 0;\n \n-\t\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&line, in) != EOF) {\n \t\t\tif (!strcmp(reference, line.buf)) {\n \t\t\t\tfound = 1;\n \t\t\t\tbreak;\ndiff --git a/shell.c b/shell.c\nindex ace62e4..c5439a6 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -88,7 +88,7 @@ static void run_shell(void)\n \t\tint count;\n \n \t\tfprintf(stderr, \"git> \");\n-\t\tif (strbuf_getline(&line, stdin, '\\n') == EOF) {\n+\t\tif (strbuf_getline_lf(&line, stdin) == EOF) {\n \t\t\tfprintf(stderr, \"\\n\");\n \t\t\tstrbuf_release(&line);\n \t\t\tbreak;\ndiff --git a/strbuf.c b/strbuf.c\nindex 7ad5ea4..2ff898c 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -522,6 +522,16 @@ int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n \treturn 0;\n }\n \n+int strbuf_getline_lf(struct strbuf *sb, FILE *fp)\n+{\n+\treturn strbuf_getline(sb, fp, '\\n');\n+}\n+\n+int strbuf_getline_nul(struct strbuf *sb, FILE *fp)\n+{\n+\treturn strbuf_getline(sb, fp, '\\0');\n+}\n+\n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\n {\n \tstrbuf_reset(sb);\ndiff --git a/strbuf.h b/strbuf.h\nindex d84c866..5501743 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -388,6 +388,12 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  */\n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+\n+typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n+\n+extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n+extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n+\n /*\n  * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n  * and additionally treats a '\\r' that comes immediately before '\\n'\n@@ -395,6 +401,7 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);\n  */\n extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n \n+\n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\n  * any) in the buffer.\ndiff --git a/test-sha1-array.c b/test-sha1-array.c\nindex ddc491e..700f3f3 100644\n--- a/test-sha1-array.c\n+++ b/test-sha1-array.c\n@@ -11,7 +11,7 @@ int main(int argc, char **argv)\n \tstruct sha1_array array = SHA1_ARRAY_INIT;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, stdin) != EOF) {\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 63d5427..74eb217 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)\n \tstrbuf_reset(buffer);\n \tif (debug)\n \t\tfprintf(stderr, \"Debug: Remote helper: Waiting...\\n\");\n-\tif (strbuf_getline(buffer, helper, '\\n') == EOF) {\n+\tif (strbuf_getline_lf(buffer, helper) == EOF) {\n \t\tif (debug)\n \t\t\tfprintf(stderr, \"Debug: Remote helper quit.\\n\");\n \t\treturn 1;\ndiff --git a/walker.c b/walker.c\nindex cdeb63f..7615857 100644\n--- a/walker.c\n+++ b/walker.c\n@@ -220,7 +220,7 @@ int walker_targets_stdin(char ***target, const char ***write_ref)\n \t\tchar *rf_one = NULL;\n \t\tchar *tg_one;\n \n-\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(&buf, stdin) == EOF)\n \t\t\tbreak;\n \t\ttg_one = buf.buf;\n \t\trf_one = strchr(tg_one, '\\t');\ndiff --git a/wt-status.c b/wt-status.c\nindex 3e3b8c0..7aa3d1b 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -988,7 +988,7 @@ static char *read_line_from_git_path(const char *filename)\n \t\tstrbuf_release(&buf);\n \t\treturn NULL;\n \t}\n-\tstrbuf_getline(&buf, fp, '\\n');\n+\tstrbuf_getline_lf(&buf, fp);\n \tif (!fclose(fp)) {\n \t\treturn strbuf_detach(&buf, NULL);\n \t} else {\n@@ -1076,7 +1076,7 @@ static void read_rebase_todolist(const char *fname, struct string_list *lines)\n \tif (!f)\n \t\tdie_errno(\"Could not open file %s for reading\",\n \t\t\t  git_path(\"%s\", fname));\n-\twhile (!strbuf_getline(&line, f, '\\n')) {\n+\twhile (!strbuf_getline_lf(&line, f)) {\n \t\tif (line.len && line.buf[0] == comment_line_char)\n \t\t\tcontinue;\n \t\tstrbuf_trim(&line);\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275994","messageId":"1452740590-16827-5-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 4/9] mktree: there are only two line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:04Z","receivedAt":"2016-01-14T03:03:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default works on LF terminated lines, with an option\nto use NUL terminated records.  Instead of pretending that there can\nbe other useful values that can be stuffed into line_termination,\nmake it a boolean \"lf_lines\", and switch between strbuf_getline_{lf,nul}\nbased on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mktree.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a964d6b..00e9b7e 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -65,7 +65,7 @@ static const char *mktree_usage[] = {\n \tNULL\n };\n \n-static void mktree_line(char *buf, size_t len, int line_termination, int allow_missing)\n+static void mktree_line(char *buf, size_t len, int lf_lines, int allow_missing)\n {\n \tchar *ptr, *ntr;\n \tunsigned mode;\n@@ -97,7 +97,7 @@ static void mktree_line(char *buf, size_t len, int line_termination, int allow_m\n \t*ntr++ = 0; /* now at the beginning of SHA1 */\n \n \tpath = ntr + 41;  /* at the beginning of name */\n-\tif (line_termination && path[0] == '\"') {\n+\tif (lf_lines && path[0] == '\"') {\n \t\tstruct strbuf p_uq = STRBUF_INIT;\n \t\tif (unquote_c_style(&p_uq, path, NULL))\n \t\t\tdie(\"invalid quoting\");\n@@ -141,23 +141,25 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tunsigned char sha1[20];\n-\tint line_termination = '\\n';\n+\tint lf_lines = 1;\n \tint allow_missing = 0;\n \tint is_batch_mode = 0;\n \tint got_eof = 0;\n+\tstrbuf_getline_fn getline_fn;\n \n \tconst struct option option[] = {\n-\t\tOPT_SET_INT('z', NULL, &line_termination, N_(\"input is NUL terminated\"), '\\0'),\n+\t\tOPT_SET_INT('z', NULL, &lf_lines, N_(\"input is NUL terminated\"), '\\0'),\n \t\tOPT_SET_INT( 0 , \"missing\", &allow_missing, N_(\"allow missing objects\"), 1),\n \t\tOPT_SET_INT( 0 , \"batch\", &is_batch_mode, N_(\"allow creation of more than one tree\"), 1),\n \t\tOPT_END()\n \t};\n \n \tac = parse_options(ac, av, prefix, option, mktree_usage, 0);\n+\tgetline_fn = lf_lines ? strbuf_getline_lf : strbuf_getline_nul;\n \n \twhile (!got_eof) {\n \t\twhile (1) {\n-\t\t\tif (strbuf_getline(&sb, stdin, line_termination) == EOF) {\n+\t\t\tif (getline_fn(&sb, stdin) == EOF) {\n \t\t\t\tgot_eof = 1;\n \t\t\t\tbreak;\n \t\t\t}\n@@ -167,7 +169,7 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n \t\t\t\t\tbreak;\n \t\t\t\tdie(\"input format error: (blank line only valid in batch mode)\");\n \t\t\t}\n-\t\t\tmktree_line(sb.buf, sb.len, line_termination, allow_missing);\n+\t\t\tmktree_line(sb.buf, sb.len, lf_lines, allow_missing);\n \t\t}\n \t\tif (is_batch_mode && got_eof && used < 1) {\n \t\t\t/*\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275995","messageId":"1452740590-16827-6-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 5/9] check-attr: there are only two line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:05Z","receivedAt":"2016-01-14T03:03:05Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default works on LF terminated lines, with an option\nto use NUL terminated records.  Instead of using line_termination\nthat happens to take LF or NUL, use the value of nul_term_line and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/check-attr.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 265c9ba..087325e 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -73,12 +73,13 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n \tstruct git_attr_check *check)\n {\n \tstruct strbuf buf, nbuf;\n-\tint line_termination = nul_term_line ? 0 : '\\n';\n+\tstrbuf_getline_fn getline_fn;\n \n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n-\t\tif (line_termination && buf.buf[0] == '\"') {\n+\twhile (getline_fn(&buf, stdin) != EOF) {\n+\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275996","messageId":"1452740590-16827-7-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 6/9] check-ignore: there are only two line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:06Z","receivedAt":"2016-01-14T03:03:06Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default works on LF terminated lines, with an option\nto use NUL terminated records.  Instead of using line_termination\nthat happens to take LF or NUL, use the value of nul_term_line and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/check-ignore.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 43f3617..4f0b09e 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -117,13 +117,14 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n {\n \tstruct strbuf buf, nbuf;\n \tchar *pathspec[2] = { NULL, NULL };\n-\tint line_termination = nul_term_line ? 0 : '\\n';\n+\tstrbuf_getline_fn getline_fn;\n \tint num_ignored = 0;\n \n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n-\t\tif (line_termination && buf.buf[0] == '\"') {\n+\twhile (getline_fn(&buf, stdin) != EOF) {\n+\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275999","messageId":"1452740590-16827-8-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 7/9] update-index: there are only two line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:07Z","receivedAt":"2016-01-14T03:03:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default works on LF terminated lines, with an option\nto use NUL terminated records, when reading the index-info and\ncacheinfo.  Instead of using line_termination that happens to take\nLF or NUL, use the value of nul_term_line and switch between\nstrbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/update-index.c | 27 ++++++++++++++++-----------\n 1 file changed, 16 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 7431938..6d90424 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -468,12 +468,14 @@ static void update_one(const char *path)\n \treport(\"add '%s'\", path);\n }\n \n-static void read_index_info(int line_termination)\n+static void read_index_info(int nul_term_line)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf uq = STRBUF_INIT;\n+\tstrbuf_getline_fn getline_fn;\n \n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n+\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\tchar *ptr, *tab;\n \t\tchar *path_name;\n \t\tunsigned char sha1[20];\n@@ -522,7 +524,7 @@ static void read_index_info(int line_termination)\n \t\t\tgoto bad_line;\n \n \t\tpath_name = ptr;\n-\t\tif (line_termination && path_name[0] == '\"') {\n+\t\tif (!nul_term_line && path_name[0] == '\"') {\n \t\t\tstrbuf_reset(&uq);\n \t\t\tif (unquote_c_style(&uq, path_name, NULL)) {\n \t\t\t\tdie(\"git update-index: bad quoting of path name\");\n@@ -844,12 +846,12 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,\n static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,\n \t\t\t      const struct option *opt, int unset)\n {\n-\tint *line_termination = opt->value;\n+\tint *nul_term_line = opt->value;\n \n \tif (ctx->argc != 1)\n \t\treturn error(\"option '%s' must be the last argument\", opt->long_name);\n \tallow_add = allow_replace = allow_remove = 1;\n-\tread_index_info(*line_termination);\n+\tread_index_info(*nul_term_line);\n \treturn 0;\n }\n \n@@ -901,7 +903,7 @@ static int reupdate_callback(struct parse_opt_ctx_t *ctx,\n \n int cmd_update_index(int argc, const char **argv, const char *prefix)\n {\n-\tint newfd, entries, has_errors = 0, line_termination = '\\n';\n+\tint newfd, entries, has_errors = 0, nul_term_line = 0;\n \tint untracked_cache = -1;\n \tint read_from_stdin = 0;\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n@@ -912,6 +914,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \tint split_index = -1;\n \tstruct lock_file *lock_file;\n \tstruct parse_opt_ctx_t ctx;\n+\tstrbuf_getline_fn getline_fn;\n \tint parseopt_state = PARSE_OPT_UNKNOWN;\n \tstruct option options[] = {\n \t\tOPT_BIT('q', NULL, &refresh_args.flags,\n@@ -963,13 +966,13 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"add to index only; do not add content to object database\"), 1),\n \t\tOPT_SET_INT(0, \"force-remove\", &force_remove,\n \t\t\tN_(\"remove named paths even if present in worktree\"), 1),\n-\t\tOPT_SET_INT('z', NULL, &line_termination,\n-\t\t\tN_(\"with --stdin: input lines are terminated by null bytes\"), '\\0'),\n+\t\tOPT_SET_INT('z', NULL, &nul_term_line,\n+\t\t\t    N_(\"with --stdin: input lines are terminated by null bytes\"), 1),\n \t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"stdin\", &read_from_stdin, NULL,\n \t\t\tN_(\"read list of paths to be updated from standard input\"),\n \t\t\tPARSE_OPT_NONEG | PARSE_OPT_NOARG,\n \t\t\t(parse_opt_cb *) stdin_callback},\n-\t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"index-info\", &line_termination, NULL,\n+\t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"index-info\", &nul_term_line, NULL,\n \t\t\tN_(\"add entries from standard input to the index\"),\n \t\t\tPARSE_OPT_NONEG | PARSE_OPT_NOARG,\n \t\t\t(parse_opt_cb *) stdin_cacheinfo_callback},\n@@ -1057,6 +1060,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \targc = parse_options_end(&ctx);\n+\n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \tif (preferred_index_format) {\n \t\tif (preferred_index_format < INDEX_FORMAT_LB ||\n \t\t    INDEX_FORMAT_UB < preferred_index_format)\n@@ -1073,9 +1078,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n \t\tsetup_work_tree();\n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\t\tchar *p;\n-\t\t\tif (line_termination && buf.buf[0] == '\"') {\n+\t\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n \t\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275998","messageId":"1452740590-16827-9-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 8/9] checkout-index: there are only two line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:08Z","receivedAt":"2016-01-14T03:03:08Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default works on LF terminated lines, with an option\nto use NUL terminated records.  Instead of using line_termination\nthat happens to take LF or NUL to call strbuf_getline(), switch\nbetween strbuf_getline_{lf,nul} based on the value of '-z' option.\n\nNote that this still leaves the option open to use NUL-terminated\ninput mixed with LF-terminated output (and vice versa), and even\nHT-terminated output is still left as a possibility, because this\nseries is only interested in tightening the overly broad interface\non the input side.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout-index.c | 10 +++++++---\n 1 file changed, 7 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 8028c37..0368e0d 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -12,6 +12,7 @@\n \n #define CHECKOUT_ALL 4\n static int line_termination = '\\n';\n+static strbuf_getline_fn getline_fn = strbuf_getline_lf;\n static int checkout_stage; /* default to checkout stage0 */\n static int to_tempfile;\n static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];\n@@ -144,10 +145,13 @@ static int option_parse_u(const struct option *opt,\n static int option_parse_z(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n-\tif (unset)\n+\tif (unset) {\n \t\tline_termination = '\\n';\n-\telse\n+\t\tgetline_fn = strbuf_getline_lf;\n+\t} else {\n \t\tline_termination = 0;\n+\t\tgetline_fn = strbuf_getline_nul;\n+\t}\n \treturn 0;\n }\n \n@@ -258,7 +262,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\tif (all)\n \t\t\tdie(\"git checkout-index: don't mix '--all' and '--stdin'\");\n \n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (line_termination && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n-- \n2.7.0-242-gdd583c7\n"},{"id":"275997","messageId":"1452740590-16827-10-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 9/9] strbuf: give strbuf_getline() to the \"most text friendly\" variant","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:09Z","receivedAt":"2016-01-14T03:03:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Now there is no direct caller to strbuf_getline(), we can demote it\nto file-scope static private to strbuf.c implementation and rename\nit to strbuf_getdelim().  Rename strbuf_getline_crlf(), which is\ndesigned to be the most \"text friendly\" variant, and allow it to\ntake over this simplest name, strbuf_getline(), so we can add more\nuses of it without having to type _crlf over and over again in the\ncoming steps.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c       |  8 ++++----\n strbuf.c           |  8 ++++----\n strbuf.h           | 25 ++++++++++++++-----------\n transport-helper.c |  3 ++-\n 4 files changed, 24 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 885fa19..8e3a9f9 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -612,7 +612,7 @@ static int is_mail(FILE *fp)\n \tif (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))\n \t\tdie(\"invalid pattern: %s\", header_regex);\n \n-\twhile (!strbuf_getline_crlf(&sb, fp)) {\n+\twhile (!strbuf_getline(&sb, fp)) {\n \t\tif (!sb.len)\n \t\t\tbreak; /* End of header */\n \n@@ -659,7 +659,7 @@ static int detect_patch_format(const char **paths)\n \n \tfp = xfopen(*paths, \"r\");\n \n-\twhile (!strbuf_getline_crlf(&l1, fp)) {\n+\twhile (!strbuf_getline(&l1, fp)) {\n \t\tif (l1.len)\n \t\t\tbreak;\n \t}\n@@ -680,9 +680,9 @@ static int detect_patch_format(const char **paths)\n \t}\n \n \tstrbuf_reset(&l2);\n-\tstrbuf_getline_crlf(&l2, fp);\n+\tstrbuf_getline(&l2, fp);\n \tstrbuf_reset(&l3);\n-\tstrbuf_getline_crlf(&l3, fp);\n+\tstrbuf_getline(&l3, fp);\n \n \t/*\n \t * If the second line is empty and the third is a From, Author or Date\ndiff --git a/strbuf.c b/strbuf.c\nindex 2ff898c..47ac045 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -501,7 +501,7 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)\n }\n #endif\n \n-int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n+static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n@@ -510,7 +510,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n \treturn 0;\n }\n \n-int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n+int strbuf_getline(struct strbuf *sb, FILE *fp)\n {\n \tif (strbuf_getwholeline(sb, fp, '\\n'))\n \t\treturn EOF;\n@@ -524,12 +524,12 @@ int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n \n int strbuf_getline_lf(struct strbuf *sb, FILE *fp)\n {\n-\treturn strbuf_getline(sb, fp, '\\n');\n+\treturn strbuf_getdelim(sb, fp, '\\n');\n }\n \n int strbuf_getline_nul(struct strbuf *sb, FILE *fp)\n {\n-\treturn strbuf_getline(sb, fp, '\\0');\n+\treturn strbuf_getdelim(sb, fp, '\\0');\n }\n \n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\ndiff --git a/strbuf.h b/strbuf.h\nindex 5501743..220c541 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -354,8 +354,8 @@ extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm\n  *\n  * NOTE: The buffer is rewound if the read fails. If -1 is returned,\n  * `errno` must be consulted, like you would do for `read(3)`.\n- * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the\n- * same behaviour as well.\n+ * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline_*()`\n+ * family of functions have the same behaviour as well.\n  */\n extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n \n@@ -380,26 +380,29 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n \n /**\n  * Read a line from a FILE *, overwriting the existing contents\n- * of the strbuf. The second argument specifies the line\n- * terminator character, typically `'\\n'`.\n+ * of the strbuf.  There are three public functions with this\n+ * function signature, with different line termination convention.\n  * Reading stops after the terminator or at EOF.  The terminator\n  * is removed from the buffer before returning.  Returns 0 unless\n  * there was nothing left before EOF, in which case it returns `EOF`.\n  */\n-extern int strbuf_getline(struct strbuf *, FILE *, int);\n-\n \n typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n \n+/* Uses LF as the line terminator */\n extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n+\n+/* Uses NUL as the line terminator */\n extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n \n-/*\n- * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n- * and additionally treats a '\\r' that comes immediately before '\\n'\n- * as part of the terminator.\n+/**\n+ * Similar to strbuf_getline_lf(), but additionally treats\n+ * a '\\r' that comes immediately before '\\n' as part of the\n+ * terminator.  This is the most friendly version to be used\n+ * to read \"text\" files that can come from platforms whose\n+ * native text format is CRLF terminated.\n  */\n-extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n+extern int strbuf_getline(struct strbuf *, FILE *);\n \n \n /**\ndiff --git a/transport-helper.c b/transport-helper.c\nindex 74eb217..d108336 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -137,7 +137,8 @@ static struct child_process *get_helper(struct transport *transport)\n \tdata->no_disconnect_req = 0;\n \n \t/*\n-\t * Open the output as FILE* so strbuf_getline() can be used.\n+\t * Open the output as FILE* so strbuf_getline_*() family of\n+\t * functions can be used.\n \t * Do this with duped fd because fclose() will close the fd,\n \t * and stuff like taking over will require the fd to remain.\n \t */\n-- \n2.7.0-242-gdd583c7\n"},{"id":"276000","messageId":"1452740590-16827-11-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PREVIEW v3 9/9] strbuf: retire strbuf_getline() for now","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:03:10Z","receivedAt":"2016-01-14T03:03:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Now there is no direct caller to strbuf_getline(), so demote it\nto file-scope static private to strbuf.c implementation and rename\nit to strbuf_getdelim().\n\nEventually, we may want to make this short and clean name a synonym\nto strbuf_getline_crlf(), but not now.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n strbuf.c           |  6 +++---\n strbuf.h           | 21 +++++++++++----------\n transport-helper.c |  3 ++-\n 3 files changed, 16 insertions(+), 14 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 2ff898c..a8641cb 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -501,7 +501,7 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)\n }\n #endif\n \n-int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n+static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n@@ -524,12 +524,12 @@ int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n \n int strbuf_getline_lf(struct strbuf *sb, FILE *fp)\n {\n-\treturn strbuf_getline(sb, fp, '\\n');\n+\treturn strbuf_getdelim(sb, fp, '\\n');\n }\n \n int strbuf_getline_nul(struct strbuf *sb, FILE *fp)\n {\n-\treturn strbuf_getline(sb, fp, '\\0');\n+\treturn strbuf_getdelim(sb, fp, '\\0');\n }\n \n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\ndiff --git a/strbuf.h b/strbuf.h\nindex 5501743..ea2a51f 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -354,8 +354,8 @@ extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm\n  *\n  * NOTE: The buffer is rewound if the read fails. If -1 is returned,\n  * `errno` must be consulted, like you would do for `read(3)`.\n- * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the\n- * same behaviour as well.\n+ * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline_*()`\n+ * family of functions have the same behaviour as well.\n  */\n extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n \n@@ -380,24 +380,25 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n \n /**\n  * Read a line from a FILE *, overwriting the existing contents\n- * of the strbuf. The second argument specifies the line\n- * terminator character, typically `'\\n'`.\n+ * of the strbuf.  There are three public functions with this\n+ * function signature, with different line termination convention.\n  * Reading stops after the terminator or at EOF.  The terminator\n  * is removed from the buffer before returning.  Returns 0 unless\n  * there was nothing left before EOF, in which case it returns `EOF`.\n  */\n-extern int strbuf_getline(struct strbuf *, FILE *, int);\n-\n \n typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n \n+/* Uses LF as the line terminator */\n extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n+\n+/* Uses NUL as the line terminator */\n extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n \n-/*\n- * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n- * and additionally treats a '\\r' that comes immediately before '\\n'\n- * as part of the terminator.\n+/**\n+ * Similar to strbuf_getline_lf(), but additionally treats\n+ * a '\\r' that comes immediately before '\\n' as part of the\n+ * terminator.\n  */\n extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 74eb217..d108336 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -137,7 +137,8 @@ static struct child_process *get_helper(struct transport *transport)\n \tdata->no_disconnect_req = 0;\n \n \t/*\n-\t * Open the output as FILE* so strbuf_getline() can be used.\n+\t * Open the output as FILE* so strbuf_getline_*() family of\n+\t * functions can be used.\n \t * Do this with duped fd because fclose() will close the fd,\n \t * and stuff like taking over will require the fd to remain.\n \t */\n-- \n2.7.0-242-gdd583c7\n"},{"id":"276001","messageId":"xmqqd1t4luw4.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"1452740590-16827-11-git-send-email-gitster@pobox.com","subject":"Re: [PREVIEW v3 9/9] strbuf: retire strbuf_getline() for now","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T03:09:15Z","receivedAt":"2016-01-14T03:09:15Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Now there is no direct caller to strbuf_getline(), so demote it\n> to file-scope static private to strbuf.c implementation and rename\n> it to strbuf_getdelim().\n>\n> Eventually, we may want to make this short and clean name a synonym\n> to strbuf_getline_crlf(), but not now.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nThis is not part of the series but sent out by mistake.\n\n    strbuf: give strbuf_getline() to the \"most text friendly\" variant\n\n    Message-ID: <1452740590-16827-10-git-send-email-gitster@pobox.com>\n    Xref: news.gmane.org gmane.comp.version-control.git:284008\n\nis the correct 9/9.\n"},{"id":"276014","messageId":"20160114100907.GA30772@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452740590-16827-8-git-send-email-gitster@pobox.com","subject":"Re: [PREVIEW v3 7/9] update-index: there are only two line terminators","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-14T10:09:08Z","receivedAt":"2016-01-14T10:09:08Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 13, 2016 at 07:03:07PM -0800, Junio C Hamano wrote:\n\n> -static void read_index_info(int line_termination)\n> +static void read_index_info(int nul_term_line)\n>  {\n>  \tstruct strbuf buf = STRBUF_INIT;\n>  \tstruct strbuf uq = STRBUF_INIT;\n> +\tstrbuf_getline_fn getline_fn;\n>  \n> -\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n> +\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n> +\twhile (getline_fn(&buf, stdin) != EOF) {\n>  \t\tchar *ptr, *tab;\n>  \t\tchar *path_name;\n>  \t\tunsigned char sha1[20];\n> @@ -522,7 +524,7 @@ static void read_index_info(int line_termination)\n>  \t\t\tgoto bad_line;\n>  \n>  \t\tpath_name = ptr;\n> -\t\tif (line_termination && path_name[0] == '\"') {\n> +\t\tif (!nul_term_line && path_name[0] == '\"') {\n\nYikes. The original used \"line_termination\" both as a character and as a\nboolean. I think the postimage is much more obvious here.\n\n> -\t\tOPT_SET_INT('z', NULL, &line_termination,\n> -\t\t\tN_(\"with --stdin: input lines are terminated by null bytes\"), '\\0'),\n> +\t\tOPT_SET_INT('z', NULL, &nul_term_line,\n> +\t\t\t    N_(\"with --stdin: input lines are terminated by null bytes\"), 1),\n\nShould this just become OPT_BOOL now?\n\n-Peff\n"},{"id":"276015","messageId":"20160114101114.GB30772@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452740590-16827-5-git-send-email-gitster@pobox.com","subject":"Re: [PREVIEW v3 4/9] mktree: there are only two line terminators","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-14T10:11:14Z","receivedAt":"2016-01-14T10:11:14Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 13, 2016 at 07:03:04PM -0800, Junio C Hamano wrote:\n\n> @@ -141,23 +141,25 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n>  {\n>  \tstruct strbuf sb = STRBUF_INIT;\n>  \tunsigned char sha1[20];\n> -\tint line_termination = '\\n';\n> +\tint lf_lines = 1;\n>  \tint allow_missing = 0;\n>  \tint is_batch_mode = 0;\n>  \tint got_eof = 0;\n> +\tstrbuf_getline_fn getline_fn;\n>  \n>  \tconst struct option option[] = {\n> -\t\tOPT_SET_INT('z', NULL, &line_termination, N_(\"input is NUL terminated\"), '\\0'),\n> +\t\tOPT_SET_INT('z', NULL, &lf_lines, N_(\"input is NUL terminated\"), '\\0'),\n\nUsing '\\0' isn't wrong here, but should it now just be \"0\", since it's\nno longer meant to be a \"char\"?\n\nAlso, I notice that other patches in the series flip the logic (instead\nof \"lf_lines\", we get its inverse, \"nul_term_line\"). That lets us use\nthe more obvious \"OPT_BOOL\" here.\n\n-Peff\n"},{"id":"276016","messageId":"20160114101830.GC30772@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452740590-16827-9-git-send-email-gitster@pobox.com","subject":"Re: [PREVIEW v3 8/9] checkout-index: there are only two line terminators","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-14T10:18:31Z","receivedAt":"2016-01-14T10:18:31Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 13, 2016 at 07:03:08PM -0800, Junio C Hamano wrote:\n\n> The program by default works on LF terminated lines, with an option\n> to use NUL terminated records.  Instead of using line_termination\n> that happens to take LF or NUL to call strbuf_getline(), switch\n> between strbuf_getline_{lf,nul} based on the value of '-z' option.\n> \n> Note that this still leaves the option open to use NUL-terminated\n> input mixed with LF-terminated output (and vice versa), and even\n> HT-terminated output is still left as a possibility, because this\n> series is only interested in tightening the overly broad interface\n> on the input side.\n\nI see that we switch the line termination on the fly in option_parse_z.\nBut I'm having trouble seeing how we could actually have mixed inputs.\nWe don't actually look at the line-terminator until after all of the\noptions are parsed.\n\nIOW, could this OPT_CALLBACK for 'z' be simplified to a simple OPT_BOOL,\nor am I missing some case?\n\n>  #define CHECKOUT_ALL 4\n>  static int line_termination = '\\n';\n> +static strbuf_getline_fn getline_fn = strbuf_getline_lf;\n\nThis \"line_termination\" can become a boolean \"1\" now, right?\n\n> @@ -144,10 +145,13 @@ static int option_parse_u(const struct option *opt,\n>  static int option_parse_z(const struct option *opt,\n>  \t\t\t  const char *arg, int unset)\n>  {\n> -\tif (unset)\n> +\tif (unset) {\n>  \t\tline_termination = '\\n';\n> -\telse\n> +\t\tgetline_fn = strbuf_getline_lf;\n> +\t} else {\n>  \t\tline_termination = 0;\n> +\t\tgetline_fn = strbuf_getline_nul;\n> +\t}\n\nDitto here (though as before, I think I prefer it as the inverse bool:\ndid somebody turn on \"-z\").\n\nI'm also not sure how \"unset\" would trigger here. If we have a long\noption, we can use \"--no-foo\". But there isn't a long option for \"-z\".\nIs there a way to negate short options?\n\n-Peff\n"},{"id":"276018","messageId":"20160114102326.GE30772@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"Re: [PREVIEW v3 0/9] Preview of \"Peace with CRLF\" rerolled","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-14T10:23:27Z","receivedAt":"2016-01-14T10:23:27Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jan 13, 2016 at 07:03:00PM -0800, Junio C Hamano wrote:\n\n> Continued from\n> \n>  http://thread.gmane.org/gmane.comp.version-control.git/282614\n> \n> Here is only the preparatory part that\n> \n>  - introduces strbuf_getline_lf() and strbuf_getine_nul() and\n>    converts existing callers to strbut_getline() to use them;\n> \n>  - retires strbuf_getline() that takes an arbitrary line terminator\n>    and demotes it to strbuf_getdelim() that is merely an\n>    implementation detail inside strbuf.c; and\n> \n>  - gives the short-and-sweet name strbuf_getline() to the most\n>    \"text friendly\" strbuf_getline_crlf().\n\nWith the exception of a few minor nits (some of which are even just\ncleanups we _could_ do while in the area), this looks like a good\napproach to me.\n\nI'm happy that the more-immediate endgame will keep many callers with\nthe short \"strbuf_getline\" (and that its invocation is now even shorter\nand more readable than before, with the '\\n' noise gone).\n\n-Peff\n"},{"id":"276056","messageId":"xmqq8u3skrsd.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"20160114101830.GC30772@sigill.intra.peff.net","subject":"Re: [PREVIEW v3 8/9] checkout-index: there are only two line terminators","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T17:13:54Z","receivedAt":"2016-01-14T17:13:54Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I see that we switch the line termination on the fly in option_parse_z.\n> But I'm having trouble seeing how we could actually have mixed inputs.\n> We don't actually look at the line-terminator until after all of the\n> options are parsed.\n\nI do not think we are aiming for mixed inputs.  What I meant by\n\"mixed\" in my description was a possible future option to allow\ninput and output using different line termination (e.g. via \"-Z\"\nyou would control output line termination, while \"-z\" only affects\nthe input line termination).\n\nAfter this step, there is still one call that is more natural to\nhave line_termination that is either '\\0' or '\\n' and that is on the\noutput side, which calls write_name_quoted_relative() to report the\nnames of the temporary files that received the file contents to the\nstandard output.\n\nOf course there is nothing wrong to do\n\n        write_name_quoted_relative(name, prefix, stdout,\n\t\t\t\t   nul_term_lines ? '\\0' : '\\n');\n\nthough.\n\nAnd I tend to think that it might even be a good idea to do so.  If\nsomebody in the future really wants to introduce '-Z', then they can\nadd a separate \"output_line_termination\" variable back (and it would\nlikely be set to '\\0' or '\\n' via \"-z\" when \"-Z\" is not given), but\nuntil then, I agree that a simple bool for \"-z\" would be better.\n\n> I'm also not sure how \"unset\" would trigger here. If we have a long\n> option, we can use \"--no-foo\". But there isn't a long option for \"-z\".\n> Is there a way to negate short options?\n\nI do not think there is.  It merely future-proofs against those who\ntry to add \"--nul\" as a longer synonym.  They would complain after\nthey add \"--nul\" in builtin_checkout_index_options[] as a synonym if\nthey see \"--no-nul\" does not negate the effect of an earlier \"-z\".\n"},{"id":"276073","messageId":"20160114201342.GB1985@sigill.intra.peff.net","threadId":"40059","inReplyTo":"xmqq8u3skrsd.fsf@gitster.mtv.corp.google.com","subject":"Re: [PREVIEW v3 8/9] checkout-index: there are only two line terminators","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-14T20:13:43Z","receivedAt":"2016-01-14T20:13:43Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 09:13:54AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > I see that we switch the line termination on the fly in option_parse_z.\n> > But I'm having trouble seeing how we could actually have mixed inputs.\n> > We don't actually look at the line-terminator until after all of the\n> > options are parsed.\n> \n> I do not think we are aiming for mixed inputs.  What I meant by\n> \"mixed\" in my description was a possible future option to allow\n> input and output using different line termination (e.g. via \"-Z\"\n> you would control output line termination, while \"-z\" only affects\n> the input line termination).\n\nAh, I see.\n\n> After this step, there is still one call that is more natural to\n> have line_termination that is either '\\0' or '\\n' and that is on the\n> output side, which calls write_name_quoted_relative() to report the\n> names of the temporary files that received the file contents to the\n> standard output.\n> \n> Of course there is nothing wrong to do\n> \n>         write_name_quoted_relative(name, prefix, stdout,\n> \t\t\t\t   nul_term_lines ? '\\0' : '\\n');\n> \n> though.\n> \n> And I tend to think that it might even be a good idea to do so.  If\n> somebody in the future really wants to introduce '-Z', then they can\n> add a separate \"output_line_termination\" variable back (and it would\n> likely be set to '\\0' or '\\n' via \"-z\" when \"-Z\" is not given), but\n> until then, I agree that a simple bool for \"-z\" would be better.\n\nYeah, I agree with all of that.\n\n> > I'm also not sure how \"unset\" would trigger here. If we have a long\n> > option, we can use \"--no-foo\". But there isn't a long option for \"-z\".\n> > Is there a way to negate short options?\n> \n> I do not think there is.  It merely future-proofs against those who\n> try to add \"--nul\" as a longer synonym.  They would complain after\n> they add \"--nul\" in builtin_checkout_index_options[] as a synonym if\n> they see \"--no-nul\" does not negate the effect of an earlier \"-z\".\n\nMakes sense. Better still if we can turn it into OPT_BOOL, though, and\nthen it would Just Work. :)\n\n-Peff\n"},{"id":"276092","messageId":"1452815916-6447-1-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452740590-16827-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 00/21] Peace with CRLF","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:15Z","receivedAt":"2016-01-14T23:58:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We have too many topics titled \"War on something\"; let's try to make\npeace for a change.\n\nThis is a reroll of\n\n  http://thread.gmane.org/gmane.comp.version-control.git/282614\n\nwhich is a continuation to $gmane/275735, which is filed in the\narchive under another mailing list:\n\n  http://thread.gmane.org/gmane.comp.version-control.msysgit/21773\n\nbut with a larger clean-up whose early part was sent earlier, marked\nwith the \"PREVIEW v3\" label.\n\n  http://thread.gmane.org/gmane.comp.version-control.git/284001\n\nWe read \"text\" files from filesystem (or from the standard input) in\nvarious places in the code.  Some of them are written by us, but\nothers are often prepared by an editor driven by human user.  Even\nthough we write (and expect) lines in these text files to be\nterminated with LF (not CRLF), the end-user's editor can be told to\nuse CRLF termination, and on some platforms that may be the default.\n\nTypically, we use strbuf_getline() to read these \"text\" files, which\nreads a single line up to the first LF into a buffer, discard that\nLF at the end, and returns (an incomplete last line gets returned\nas-is).  Lines from a file edited on Dossy systems hence may have\na CR at the end that the end-user did not intend to be a part of it.\n\nBecause many codepaths (e.g. commit log message) first pass the\ncontents of such a file through stripspace(), and as a side effect\nof discarding the whitespace at the end of each line, lines\nterminated with CRLF are normalized to LF terminated lines (but we\ndo not lose a lone CR in the middle of a non-blank string), when we\nprocess what we read from these files, this is not a problem for\nthem, but not all of the codepaths are safe.\n\nIn these places that expect to read \"text\", we should be able to\nupdate the logic to read a line up to the first LF, discard that LF,\ntogether with a CR if one appears immediately before that LF,\nwithout breaking anything.  That includes cases where the program\nmight want to treat a CR in the middle of a line as proper payload\nthe user intended to give us.  Such a variant of strbuf_getline()\nalready exists as strbuf_getline_crlf() and used in the \"git am\"\nthat was reimplemented in C recently.\n\nThe strbuf_getline() function takes a \"line-termination\" as its\nthird argument.  Its interface is overly broad in that it allows an\narbitrary byte to be used to mark the end of a line, but in\npractice, no codepaths pass any byte other than LF or NUL.  In\ntheory, the callers that use LF as the line-termination are\nexpecting \"text\" input, so we could blindly replace them with\nstrbuf_getline_crlf() and not many things should break.  To be\nconservative, however, this series converts only chosen ones after\nauditing that such a conversion is safe.\n\nTo make the tree-wide change manageable, the early part of this\nseries first changes all callsites of strbuf_getline() to call one\nof the two new thin wrapper functions, strbuf_getline_lf() and\nstrbuf_getline_nul(), depending on the value of \"line-termination\"\nused by the caller.  This is done with Patches 1-9, which is\nessentially the same as \"PREVIEW v3\" series posted earlier, with\nsmall changes:\n\n - The update to mktree used \"lf_lines\" in the preview, but this\n   version flips it to the same \"nul_term_line\" to match other two,\n   even though I think the latter is a terrible variable name with\n   bad taste.\n\n - The update to checkout-index kept \"line_termination\" in the\n   preview, but this version no longer uses it and instead uses\n   nul_term_line.\n\n - The definition of nul_term_line for the option parser uses\n   OPT_BOOL(), as the possible values in it are true or false, not\n   '\\0' or '\\n'.\n\n - The topic was rebased on v2.7.0; the bulk of builtin/mailinfo.c\n   moved to mailinfo.c between the old base of the topic and v2.7.0,\n   so the mechanical renaming done in Patch 3 was redone.\n\nAfter Patch 9, all the original callers of strbuf_getline() that\nused LF line ending call strbuf_getline_lf().  No caller calls\nstrbuf_getline() at that point, so strbuf_getline_crlf() takes over\nthe short and nice name strbuf_getline().\n\nThe callers of strbuf_getline_lf() are inspected by the remainder of\nthe series and updated to call strbuf_getline() instead when it\nmakes sense to do so.  They all had to be updated relative to the\nprevious round (v2), but the callsites that are updated haven't\nchanged.\n\nThis series converts only the callers of strbuf_getline() that would\nmisbehave when fed a file with CRLF-terminated lines and use the\ndata with an unwanted CR appended at the end.  With the update the\ncode should work as intended with such a file, without breaking the\nexpected behaviour when working on a file with LF-terminated lines.\n\nNotes on the remaining strbuf_getline_lf() callers:\n\n * Those that expect to only read from our own output do not have to\n   accommodate CRLF-terminated lines, but they can be updated to do\n   so safely if we do not rely on the ability to express a payload\n   that has CR at the end.  For example, the insn sheet \"rebase -i\"\n   uses typically ends each line with a commit log summary that we\n   ourselves do not read or use, so even if the end-user on a\n   platform with LF lines deliberately does insert CR at the end of\n   the line and strbuf_getline() removed that CR from the payload,\n   no unexpected behaviour should happen.\n\n   It may be a good GSoC microproject to convert them to use\n   strbuf_getline().\n\n * Those that call strbuf_trim() immediately on the result before\n   doing anything, or otherwise have logic that tolerates\n   whitespaces at the end of the line, can continue using\n   strbuf_getline_lf() and will not misbehave on CRLF-terminated\n   lines.\n\n   This series does not touch them; converting them to use\n   strbuf_getline() would a good way to document them as dealing\n   with \"text\".  While doing so, they can also lose their custom\n   logic that happens to make CRLF-terminated lines work.\n\n   It is a good GSoC microproject to convert them to use\n   strbuf_getline().\n\n * Those that want to only ever see LF-terminated lines (in other\n   words, \"ABC\\r\\n\" must be treated as a line with 4 bytes payload\n   on it, A B C and CR), would be broken if we replace it with\n   strbuf_getline().  This series does not touch them, and no\n   follow-up series should, either.\n\n\nJunio C Hamano (21):\n  strbuf: miniscule style fix\n  strbuf: make strbuf_getline_crlf() global\n  strbuf: introduce strbuf_getline_{lf,nul}()\n  mktree: there are only two possible line terminations\n  check-attr: there are only two possible line terminations\n  check-ignore: there are only two possible line terminations\n  update-index: there are only two possible line terminations\n  checkout-index: there are only two possible line terminations\n  strbuf: give strbuf_getline() to the \"most text friendly\" variant\n  hash-object: read --stdin-paths with strbuf_getline()\n  revision: read --stdin with strbuf_getline()\n  rev-parse: read parseopt spec with strbuf_getline()\n  ident.c: read /etc/mailname with strbuf_getline()\n  remote.c: read $GIT_DIR/remotes/* with strbuf_getline()\n  clone/sha1_file: read info/alternates with strbuf_getline()\n  transport-helper: read helper response with strbuf_getline()\n  cat-file: read batch stream with strbuf_getline()\n  column: read lines with strbuf_getline()\n  send-pack: read list of refs with strbuf_getline()\n  grep: read -f file with strbuf_getline()\n  test-sha1-array: read command stream with strbuf_getline()\n\n bisect.c                   |  8 ++++----\n builtin/am.c               | 37 +++++++++++--------------------------\n builtin/cat-file.c         |  2 +-\n builtin/check-attr.c       |  7 ++++---\n builtin/check-ignore.c     |  7 ++++---\n builtin/check-mailmap.c    |  2 +-\n builtin/checkout-index.c   | 16 ++++++++--------\n builtin/clean.c            |  6 +++---\n builtin/clone.c            |  2 +-\n builtin/column.c           |  2 +-\n builtin/commit.c           |  2 +-\n builtin/fetch-pack.c       |  2 +-\n builtin/grep.c             |  2 +-\n builtin/hash-object.c      |  2 +-\n builtin/mktree.c           | 14 ++++++++------\n builtin/notes.c            |  2 +-\n builtin/pull.c             |  2 +-\n builtin/repack.c           |  2 +-\n builtin/rev-parse.c        |  4 ++--\n builtin/send-pack.c        |  2 +-\n builtin/update-index.c     | 27 ++++++++++++++++-----------\n compat/terminal.c          |  2 +-\n credential-cache--daemon.c |  4 ++--\n credential-store.c         |  2 +-\n credential.c               |  2 +-\n daemon.c                   |  2 +-\n fast-import.c              |  4 ++--\n ident.c                    |  2 +-\n mailinfo.c                 |  8 ++++----\n remote-curl.c              |  6 +++---\n remote-testsvn.c           |  4 ++--\n remote.c                   |  4 ++--\n revision.c                 |  9 ++-------\n sequencer.c                |  2 +-\n sha1_file.c                |  2 +-\n shell.c                    |  2 +-\n strbuf.c                   | 28 +++++++++++++++++++++++++---\n strbuf.h                   | 27 ++++++++++++++++++++++-----\n test-sha1-array.c          |  2 +-\n transport-helper.c         |  5 +++--\n walker.c                   |  2 +-\n wt-status.c                |  4 ++--\n 42 files changed, 151 insertions(+), 122 deletions(-)\n\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276091","messageId":"1452815916-6447-2-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 01/21] strbuf: miniscule style fix","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:16Z","receivedAt":"2016-01-14T23:58:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We write one SP on each side of an operator, even inside an [] pair\nthat computes the array index.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n strbuf.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex d76f0ae..b165d04 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -505,8 +505,8 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n-\tif (sb->buf[sb->len-1] == term)\n-\t\tstrbuf_setlen(sb, sb->len-1);\n+\tif (sb->buf[sb->len - 1] == term)\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n \treturn 0;\n }\n \n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276094","messageId":"1452815916-6447-3-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 02/21] strbuf: make strbuf_getline_crlf() global","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:17Z","receivedAt":"2016-01-14T23:58:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Often we read \"text\" files that are supplied by the end user\n(e.g. commit log message that was edited with $GIT_EDITOR upon 'git\ncommit -e'), and in some environments lines in a text file are\nterminated with CRLF.  Existing strbuf_getline() knows to read a\nsingle line and then strip the terminating byte from the result, but\nit is handy to have a version that is more tailored for a \"text\"\ninput that takes both '\\n' and '\\r\\n' as line terminator (aka\n<newline> in POSIX lingo) and returns the body of the line after\nstripping <newline>.\n\nRecently reimplemented \"git am\" uses such a function implemented\nprivately; move it to strbuf.[ch] and make it available for others.\n\nNote that we do not blindly replace calls to strbuf_getline() that\nuses LF as the line terminator with calls to strbuf_getline_crlf()\nand this is very much deliberate.  Some callers may want to treat an\nincoming line that ends with CR (and terminated with LF) to have a\npayload that includes the final CR, and such a blind replacement\nwill result in misconversion when done without code audit.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c | 15 ---------------\n strbuf.c     | 12 ++++++++++++\n strbuf.h     |  7 +++++++\n 3 files changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 9fb42fd..d96735c 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -46,21 +46,6 @@ static int is_empty_file(const char *filename)\n }\n \n /**\n- * Like strbuf_getline(), but treats both '\\n' and \"\\r\\n\" as line terminators.\n- */\n-static int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n-{\n-\tif (strbuf_getwholeline(sb, fp, '\\n'))\n-\t\treturn EOF;\n-\tif (sb->buf[sb->len - 1] == '\\n') {\n-\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t\tif (sb->len > 0 && sb->buf[sb->len - 1] == '\\r')\n-\t\t\tstrbuf_setlen(sb, sb->len - 1);\n-\t}\n-\treturn 0;\n-}\n-\n-/**\n  * Returns the length of the first line of msg.\n  */\n static int linelen(const char *msg)\ndiff --git a/strbuf.c b/strbuf.c\nindex b165d04..7ad5ea4 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -510,6 +510,18 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n \treturn 0;\n }\n \n+int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n+{\n+\tif (strbuf_getwholeline(sb, fp, '\\n'))\n+\t\treturn EOF;\n+\tif (sb->buf[sb->len - 1] == '\\n') {\n+\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t\tif (sb->len && sb->buf[sb->len - 1] == '\\r')\n+\t\t\tstrbuf_setlen(sb, sb->len - 1);\n+\t}\n+\treturn 0;\n+}\n+\n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\n {\n \tstrbuf_reset(sb);\ndiff --git a/strbuf.h b/strbuf.h\nindex 7123fca..d84c866 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -388,6 +388,13 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  */\n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+/*\n+ * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n+ * and additionally treats a '\\r' that comes immediately before '\\n'\n+ * as part of the terminator.\n+ */\n+extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n+\n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\n  * any) in the buffer.\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276109","messageId":"1452815916-6447-4-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 03/21] strbuf: introduce strbuf_getline_{lf,nul}()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:18Z","receivedAt":"2016-01-14T23:58:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The strbuf_getline() interface allows a byte other than LF or NUL as\nthe line terminator, but this is only because I wrote these\ncodepaths anticipating that there might be a value other than NUL\nand LF that could be useful when I introduced line_termination long\ntime ago.  No useful caller that uses other value has emerged.\n\nBy now, it is clear that the interface is overly broad without a\ngood reason.  Many codepaths have hardcoded preference to read\neither LF terminated or NUL terminated records from their input, and\nthen call strbuf_getline() with LF or NUL as the third parameter.\n\nThis step introduces two thin wrappers around strbuf_getline(),\nnamely, strbuf_getline_lf() and strbuf_getline_nul(), and\nmechanically rewrites these call sites to call either one of\nthem.  The changes contained in this patch are:\n\n * introduction of these two functions in strbuf.[ch]\n\n * mechanical conversion of all callers to strbuf_getline() with\n   either '\\n' or '\\0' as the third parameter to instead call the\n   respective thin wrapper.\n\nAfter this step, output from \"git grep 'strbuf_getline('\" would\nbecome a lot smaller.  An interim goal of this series is to make\nthis an empty set, so that we can have strbuf_getline_crlf() take\nover the shorter name strbuf_getline().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n bisect.c                   |  8 ++++----\n builtin/am.c               | 14 +++++++-------\n builtin/cat-file.c         |  2 +-\n builtin/check-mailmap.c    |  2 +-\n builtin/clean.c            |  6 +++---\n builtin/clone.c            |  2 +-\n builtin/column.c           |  2 +-\n builtin/commit.c           |  2 +-\n builtin/fetch-pack.c       |  2 +-\n builtin/grep.c             |  2 +-\n builtin/hash-object.c      |  2 +-\n builtin/notes.c            |  2 +-\n builtin/pull.c             |  2 +-\n builtin/repack.c           |  2 +-\n builtin/rev-parse.c        |  4 ++--\n builtin/send-pack.c        |  2 +-\n compat/terminal.c          |  2 +-\n credential-cache--daemon.c |  4 ++--\n credential-store.c         |  2 +-\n credential.c               |  2 +-\n daemon.c                   |  2 +-\n fast-import.c              |  4 ++--\n ident.c                    |  2 +-\n mailinfo.c                 |  8 ++++----\n remote-curl.c              |  6 +++---\n remote-testsvn.c           |  4 ++--\n remote.c                   |  4 ++--\n sequencer.c                |  2 +-\n sha1_file.c                |  2 +-\n shell.c                    |  2 +-\n strbuf.c                   | 10 ++++++++++\n strbuf.h                   |  7 +++++++\n test-sha1-array.c          |  2 +-\n transport-helper.c         |  2 +-\n walker.c                   |  2 +-\n wt-status.c                |  4 ++--\n 36 files changed, 73 insertions(+), 56 deletions(-)\n\ndiff --git a/bisect.c b/bisect.c\nindex 42aa7aa..06ec54e 100644\n--- a/bisect.c\n+++ b/bisect.c\n@@ -440,7 +440,7 @@ static void read_bisect_paths(struct argv_array *array)\n \tif (!fp)\n \t\tdie_errno(\"Could not open file '%s'\", filename);\n \n-\twhile (strbuf_getline(&str, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&str, fp) != EOF) {\n \t\tstrbuf_trim(&str);\n \t\tif (sq_dequote_to_argv_array(str.buf, array))\n \t\t\tdie(\"Badly quoted content in file '%s': %s\",\n@@ -668,7 +668,7 @@ static int is_expected_rev(const struct object_id *oid)\n \tif (!fp)\n \t\treturn 0;\n \n-\tif (strbuf_getline(&str, fp, '\\n') != EOF)\n+\tif (strbuf_getline_lf(&str, fp) != EOF)\n \t\tres = !strcmp(str.buf, oid_to_hex(oid));\n \n \tstrbuf_release(&str);\n@@ -914,9 +914,9 @@ void read_bisect_terms(const char **read_bad, const char **read_good)\n \t\t\t\tstrerror(errno));\n \t\t}\n \t} else {\n-\t\tstrbuf_getline(&str, fp, '\\n');\n+\t\tstrbuf_getline_lf(&str, fp);\n \t\t*read_bad = strbuf_detach(&str, NULL);\n-\t\tstrbuf_getline(&str, fp, '\\n');\n+\t\tstrbuf_getline_lf(&str, fp);\n \t\t*read_good = strbuf_detach(&str, NULL);\n \t}\n \tstrbuf_release(&str);\ndiff --git a/builtin/am.c b/builtin/am.c\nindex d96735c..9063a4a 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -269,7 +269,7 @@ static char *read_shell_var(FILE *fp, const char *key)\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *str;\n \n-\tif (strbuf_getline(&sb, fp, '\\n'))\n+\tif (strbuf_getline_lf(&sb, fp))\n \t\tgoto fail;\n \n \tif (!skip_prefix(sb.buf, key, &str))\n@@ -558,7 +558,7 @@ static int copy_notes_for_rebase(const struct am_state *state)\n \n \tfp = xfopen(am_path(state, \"rewritten\"), \"r\");\n \n-\twhile (!strbuf_getline(&sb, fp, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, fp)) {\n \t\tunsigned char from_obj[GIT_SHA1_RAWSZ], to_obj[GIT_SHA1_RAWSZ];\n \n \t\tif (sb.len != GIT_SHA1_HEXSZ * 2 + 1) {\n@@ -802,7 +802,7 @@ static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n \tstruct strbuf sb = STRBUF_INIT;\n \tint subject_printed = 0;\n \n-\twhile (!strbuf_getline(&sb, in, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, in)) {\n \t\tconst char *str;\n \n \t\tif (str_isspace(sb.buf))\n@@ -860,7 +860,7 @@ static int split_mail_stgit_series(struct am_state *state, const char **paths,\n \t\treturn error(_(\"could not open '%s' for reading: %s\"), *paths,\n \t\t\t\tstrerror(errno));\n \n-\twhile (!strbuf_getline(&sb, fp, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, fp)) {\n \t\tif (*sb.buf == '#')\n \t\t\tcontinue; /* skip comment lines */\n \n@@ -885,7 +885,7 @@ static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \n-\twhile (!strbuf_getline(&sb, in, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, in)) {\n \t\tconst char *str;\n \n \t\tif (skip_prefix(sb.buf, \"# User \", &str))\n@@ -1302,7 +1302,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \t/* Extract message and author information */\n \tfp = xfopen(am_path(state, \"info\"), \"r\");\n-\twhile (!strbuf_getline(&sb, fp, '\\n')) {\n+\twhile (!strbuf_getline_lf(&sb, fp)) {\n \t\tconst char *x;\n \n \t\tif (skip_prefix(sb.buf, \"Subject: \", &x)) {\n@@ -1368,7 +1368,7 @@ static int get_mail_commit_sha1(unsigned char *commit_id, const char *mail)\n \tFILE *fp = xfopen(mail, \"r\");\n \tconst char *x;\n \n-\tif (strbuf_getline(&sb, fp, '\\n'))\n+\tif (strbuf_getline_lf(&sb, fp))\n \t\treturn -1;\n \n \tif (!skip_prefix(sb.buf, \"From \", &x))\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex c0fd8db..d2ebaf1 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n \tsave_warning = warn_on_object_refname_ambiguity;\n \twarn_on_object_refname_ambiguity = 0;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\tif (data.split_on_whitespace) {\n \t\t\t/*\n \t\t\t * Split at first whitespace, tying off the beginning\ndiff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c\nindex eaaea54..cf0f54f 100644\n--- a/builtin/check-mailmap.c\n+++ b/builtin/check-mailmap.c\n@@ -54,7 +54,7 @@ int cmd_check_mailmap(int argc, const char **argv, const char *prefix)\n \n \tif (use_stdin) {\n \t\tstruct strbuf buf = STRBUF_INIT;\n-\t\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\t\tcheck_mailmap(&mailmap, buf.buf);\n \t\t\tmaybe_flush_or_die(stdout, \"stdout\");\n \t\t}\ndiff --git a/builtin/clean.c b/builtin/clean.c\nindex d7acb94..cc5f972 100644\n--- a/builtin/clean.c\n+++ b/builtin/clean.c\n@@ -594,7 +594,7 @@ static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)\n \t\t\t       clean_get_color(CLEAN_COLOR_RESET));\n \t\t}\n \n-\t\tif (strbuf_getline(&choice, stdin, '\\n') != EOF) {\n+\t\tif (strbuf_getline_lf(&choice, stdin) != EOF) {\n \t\t\tstrbuf_trim(&choice);\n \t\t} else {\n \t\t\teof = 1;\n@@ -676,7 +676,7 @@ static int filter_by_patterns_cmd(void)\n \t\tclean_print_color(CLEAN_COLOR_PROMPT);\n \t\tprintf(_(\"Input ignore patterns>> \"));\n \t\tclean_print_color(CLEAN_COLOR_RESET);\n-\t\tif (strbuf_getline(&confirm, stdin, '\\n') != EOF)\n+\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF)\n \t\t\tstrbuf_trim(&confirm);\n \t\telse\n \t\t\tputchar('\\n');\n@@ -774,7 +774,7 @@ static int ask_each_cmd(void)\n \t\t\tqname = quote_path_relative(item->string, NULL, &buf);\n \t\t\t/* TRANSLATORS: Make sure to keep [y/N] as is */\n \t\t\tprintf(_(\"Remove %s [y/N]? \"), qname);\n-\t\t\tif (strbuf_getline(&confirm, stdin, '\\n') != EOF) {\n+\t\t\tif (strbuf_getline_lf(&confirm, stdin) != EOF) {\n \t\t\t\tstrbuf_trim(&confirm);\n \t\t\t} else {\n \t\t\t\tputchar('\\n');\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex a0b3cd9..29741f4 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n \tFILE *in = fopen(src->buf, \"r\");\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, in) != EOF) {\n \t\tchar *abs_path;\n \t\tif (!line.len || line.buf[0] == '#')\n \t\t\tcontinue;\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 449413c..40eab08 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--command must be the first argument\"));\n \t}\n \tfinalize_colopts(&colopts, -1);\n-\twhile (!strbuf_getline(&sb, stdin, '\\n'))\n+\twhile (!strbuf_getline_lf(&sb, stdin))\n \t\tstring_list_append(&list, sb.buf);\n \n \tprint_columns(&list, colopts, &copts);\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex d054f84..d9db59e 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1690,7 +1690,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tif (fp == NULL)\n \t\t\tdie_errno(_(\"could not open '%s' for reading\"),\n \t\t\t\t  git_path_merge_head());\n-\t\twhile (strbuf_getline(&m, fp, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&m, fp) != EOF) {\n \t\t\tstruct commit *parent;\n \n \t\t\tparent = get_merge_parent(m.buf);\ndiff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c\nindex cf3019e..9b2a514 100644\n--- a/builtin/fetch-pack.c\n+++ b/builtin/fetch-pack.c\n@@ -158,7 +158,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)\n \t\telse {\n \t\t\t/* read from stdin one ref per line, until EOF */\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline(&line, stdin, '\\n') != EOF)\n+\t\t\twhile (strbuf_getline_lf(&line, stdin) != EOF)\n \t\t\t\tadd_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 4229cae..5a5beb8 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -562,7 +562,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n-\twhile (strbuf_getline(&sb, patterns, '\\n') == 0) {\n+\twhile (strbuf_getline_lf(&sb, patterns) == 0) {\n \t\t/* ignore empty line like grep does */\n \t\tif (sb.len == 0)\n \t\t\tcontinue;\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 43b098b..3bc5ec1 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n {\n \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 52aa9af..3775e38 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -290,7 +290,7 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)\n \t\tt = &default_notes_tree;\n \t}\n \n-\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n \t\tunsigned char from_obj[20], to_obj[20];\n \t\tstruct strbuf **split;\n \t\tint err;\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex 5145fc6..52606a8 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -378,7 +378,7 @@ static void get_merge_heads(struct sha1_array *merge_heads)\n \n \tif (!(fp = fopen(filename, \"r\")))\n \t\tdie_errno(_(\"could not open '%s' for reading\"), filename);\n-\twhile (strbuf_getline(&sb, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&sb, fp) != EOF) {\n \t\tif (get_sha1_hex(sb.buf, sha1))\n \t\t\tcontinue;  /* invalid line: does not start with SHA1 */\n \t\tif (starts_with(sb.buf + GIT_SHA1_HEXSZ, \"\\tnot-for-merge\\t\"))\ndiff --git a/builtin/repack.c b/builtin/repack.c\nindex 9456110..858db38 100644\n--- a/builtin/repack.c\n+++ b/builtin/repack.c\n@@ -266,7 +266,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)\n \t\treturn ret;\n \n \tout = xfdopen(cmd.out, \"r\");\n-\twhile (strbuf_getline(&line, out, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, out) != EOF) {\n \t\tif (line.len != 40)\n \t\t\tdie(\"repack: Expecting 40 character sha1 lines only from pack-objects.\");\n \t\tstring_list_append(&names, line.buf);\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 7e074aa..0324abb 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -383,7 +383,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \n \t/* get the usage up to the first line with a -- on it */\n \tfor (;;) {\n-\t\tif (strbuf_getline(&sb, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(&sb, stdin) == EOF)\n \t\t\tdie(\"premature end of input\");\n \t\tALLOC_GROW(usage, unb + 1, usz);\n \t\tif (!strcmp(\"--\", sb.buf)) {\n@@ -396,7 +396,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */\n-\twhile (strbuf_getline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&sb, stdin) != EOF) {\n \t\tconst char *s;\n \t\tconst char *help;\n \t\tstruct option *o;\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex f6e5d64..8f9f4f1 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targv_array_push(&all_refspecs, buf);\n \t\t} else {\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline(&line, stdin, '\\n') != EOF)\n+\t\t\twhile (strbuf_getline_lf(&line, stdin) != EOF)\n \t\t\t\targv_array_push(&all_refspecs, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\ndiff --git a/compat/terminal.c b/compat/terminal.c\nindex 313897d..fa13ee6 100644\n--- a/compat/terminal.c\n+++ b/compat/terminal.c\n@@ -122,7 +122,7 @@ char *git_terminal_prompt(const char *prompt, int echo)\n \tfputs(prompt, output_fh);\n \tfflush(output_fh);\n \n-\tr = strbuf_getline(&buf, input_fh, '\\n');\n+\tr = strbuf_getline_lf(&buf, input_fh);\n \tif (!echo) {\n \t\tputc('\\n', output_fh);\n \t\tfflush(output_fh);\ndiff --git a/credential-cache--daemon.c b/credential-cache--daemon.c\nindex 9365f2c..cc65a9c 100644\n--- a/credential-cache--daemon.c\n+++ b/credential-cache--daemon.c\n@@ -96,12 +96,12 @@ static int read_request(FILE *fh, struct credential *c,\n \tstatic struct strbuf item = STRBUF_INIT;\n \tconst char *p;\n \n-\tstrbuf_getline(&item, fh, '\\n');\n+\tstrbuf_getline_lf(&item, fh);\n \tif (!skip_prefix(item.buf, \"action=\", &p))\n \t\treturn error(\"client sent bogus action line: %s\", item.buf);\n \tstrbuf_addstr(action, p);\n \n-\tstrbuf_getline(&item, fh, '\\n');\n+\tstrbuf_getline_lf(&item, fh);\n \tif (!skip_prefix(item.buf, \"timeout=\", &p))\n \t\treturn error(\"client sent bogus timeout line: %s\", item.buf);\n \t*timeout = atoi(p);\ndiff --git a/credential-store.c b/credential-store.c\nindex 54c4e04..5714167 100644\n--- a/credential-store.c\n+++ b/credential-store.c\n@@ -23,7 +23,7 @@ static int parse_credential_file(const char *fn,\n \t\treturn found_credential;\n \t}\n \n-\twhile (strbuf_getline(&line, fh, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, fh) != EOF) {\n \t\tcredential_from_url(&entry, line.buf);\n \t\tif (entry.username && entry.password &&\n \t\t    credential_match(c, &entry)) {\ndiff --git a/credential.c b/credential.c\nindex b146ad8..7d6501d 100644\n--- a/credential.c\n+++ b/credential.c\n@@ -142,7 +142,7 @@ int credential_read(struct credential *c, FILE *fp)\n {\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, fp) != EOF) {\n \t\tchar *key = line.buf;\n \t\tchar *value = strchr(key, '=');\n \ndiff --git a/daemon.c b/daemon.c\nindex be70cd4..46b411c 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -424,7 +424,7 @@ static void copy_to_log(int fd)\n \t\treturn;\n \t}\n \n-\twhile (strbuf_getline(&line, fp, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, fp) != EOF) {\n \t\tlogerror(\"%s\", line.buf);\n \t\tstrbuf_setlen(&line, 0);\n \t}\ndiff --git a/fast-import.c b/fast-import.c\nindex 3c65edb..bf01b34 100644\n--- a/fast-import.c\n+++ b/fast-import.c\n@@ -1888,7 +1888,7 @@ static int read_next_command(void)\n \t\t\tstruct recent_command *rc;\n \n \t\t\tstrbuf_detach(&command_buf, NULL);\n-\t\t\tstdin_eof = strbuf_getline(&command_buf, stdin, '\\n');\n+\t\t\tstdin_eof = strbuf_getline_lf(&command_buf, stdin);\n \t\t\tif (stdin_eof)\n \t\t\t\treturn EOF;\n \n@@ -1960,7 +1960,7 @@ static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)\n \n \t\tstrbuf_detach(&command_buf, NULL);\n \t\tfor (;;) {\n-\t\t\tif (strbuf_getline(&command_buf, stdin, '\\n') == EOF)\n+\t\t\tif (strbuf_getline_lf(&command_buf, stdin) == EOF)\n \t\t\t\tdie(\"EOF in data (terminator '%s' not found)\", term);\n \t\t\tif (term_len == command_buf.len\n \t\t\t\t&& !strcmp(term, command_buf.buf))\ndiff --git a/ident.c b/ident.c\nindex daf7e1e..9dd3ae3 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -76,7 +76,7 @@ static int add_mailname_host(struct strbuf *buf)\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\tif (strbuf_getline(&mailnamebuf, mailname, '\\n') == EOF) {\n+\tif (strbuf_getline_lf(&mailnamebuf, mailname) == EOF) {\n \t\tif (ferror(mailname))\n \t\t\twarning(\"cannot read /etc/mailname: %s\",\n \t\t\t\tstrerror(errno));\ndiff --git a/mailinfo.c b/mailinfo.c\nindex f289941..9f19ca1 100644\n--- a/mailinfo.c\n+++ b/mailinfo.c\n@@ -732,7 +732,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in)\n \tstruct strbuf continuation = STRBUF_INIT;\n \n \t/* Get the first part of the line. */\n-\tif (strbuf_getline(line, in, '\\n'))\n+\tif (strbuf_getline_lf(line, in))\n \t\treturn 0;\n \n \t/*\n@@ -756,7 +756,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in)\n \t\tpeek = fgetc(in); ungetc(peek, in);\n \t\tif (peek != ' ' && peek != '\\t')\n \t\t\tbreak;\n-\t\tif (strbuf_getline(&continuation, in, '\\n'))\n+\t\tif (strbuf_getline_lf(&continuation, in))\n \t\t\tbreak;\n \t\tcontinuation.buf[0] = ' ';\n \t\tstrbuf_rtrim(&continuation);\n@@ -769,7 +769,7 @@ static int read_one_header_line(struct strbuf *line, FILE *in)\n \n static int find_boundary(struct mailinfo *mi, struct strbuf *line)\n {\n-\twhile (!strbuf_getline(line, mi->input, '\\n')) {\n+\twhile (!strbuf_getline_lf(line, mi->input)) {\n \t\tif (*(mi->content_top) && is_multipart_boundary(mi, line))\n \t\t\treturn 1;\n \t}\n@@ -820,7 +820,7 @@ again:\n \n \tstrbuf_release(&newline);\n \t/* replenish line */\n-\tif (strbuf_getline(line, mi->input, '\\n'))\n+\tif (strbuf_getline_lf(line, mi->input))\n \t\treturn 0;\n \tstrbuf_addch(line, '\\n');\n \treturn 1;\ndiff --git a/remote-curl.c b/remote-curl.c\nindex f404faf..c704857 100644\n--- a/remote-curl.c\n+++ b/remote-curl.c\n@@ -827,7 +827,7 @@ static void parse_fetch(struct strbuf *buf)\n \t\t\tdie(\"http transport does not support %s\", buf->buf);\n \n \t\tstrbuf_reset(buf);\n-\t\tif (strbuf_getline(buf, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(buf, stdin) == EOF)\n \t\t\treturn;\n \t\tif (!*buf->buf)\n \t\t\tbreak;\n@@ -940,7 +940,7 @@ static void parse_push(struct strbuf *buf)\n \t\t\tdie(\"http transport does not support %s\", buf->buf);\n \n \t\tstrbuf_reset(buf);\n-\t\tif (strbuf_getline(buf, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(buf, stdin) == EOF)\n \t\t\tgoto free_specs;\n \t\tif (!*buf->buf)\n \t\t\tbreak;\n@@ -990,7 +990,7 @@ int main(int argc, const char **argv)\n \tdo {\n \t\tconst char *arg;\n \n-\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF) {\n+\t\tif (strbuf_getline_lf(&buf, stdin) == EOF) {\n \t\t\tif (ferror(stdin))\n \t\t\t\terror(\"remote-curl: error reading command stream from git\");\n \t\t\treturn 1;\ndiff --git a/remote-testsvn.c b/remote-testsvn.c\nindex f599c37..f05ff45 100644\n--- a/remote-testsvn.c\n+++ b/remote-testsvn.c\n@@ -154,7 +154,7 @@ static void check_or_regenerate_marks(int latestrev)\n \t\tfclose(marksfile);\n \t} else {\n \t\tstrbuf_addf(&sb, \":%d \", latestrev);\n-\t\twhile (strbuf_getline(&line, marksfile, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&line, marksfile) != EOF) {\n \t\t\tif (starts_with(line.buf, sb.buf)) {\n \t\t\t\tfound++;\n \t\t\t\tbreak;\n@@ -322,7 +322,7 @@ int main(int argc, char **argv)\n \tmarksfilename = marksfilename_sb.buf;\n \n \twhile (1) {\n-\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF) {\n+\t\tif (strbuf_getline_lf(&buf, stdin) == EOF) {\n \t\t\tif (ferror(stdin))\n \t\t\t\tdie(\"Error reading command stream\");\n \t\t\telse\ndiff --git a/remote.c b/remote.c\nindex 9d34b5a..f195693 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \tremote->origin = REMOTE_REMOTES;\n-\twhile (strbuf_getline(&buf, f, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&buf, f) != EOF) {\n \t\tconst char *v;\n \n \t\tstrbuf_rtrim(&buf);\n@@ -281,7 +281,7 @@ static void read_branches_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \n-\tstrbuf_getline(&buf, f, '\\n');\n+\tstrbuf_getline_lf(&buf, f);\n \tfclose(f);\n \tstrbuf_trim(&buf);\n \tif (!buf.len) {\ndiff --git a/sequencer.c b/sequencer.c\nindex 8c58fa2..8048786 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -886,7 +886,7 @@ static int sequencer_rollback(struct replay_opts *opts)\n \tif (!f)\n \t\treturn error(_(\"cannot open %s: %s\"), git_path_head_file(),\n \t\t\t\t\t\tstrerror(errno));\n-\tif (strbuf_getline(&buf, f, '\\n')) {\n+\tif (strbuf_getline_lf(&buf, f)) {\n \t\terror(_(\"cannot read %s: %s\"), git_path_head_file(),\n \t\t      ferror(f) ?  strerror(errno) : _(\"unexpected end of file\"));\n \t\tfclose(f);\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 73ccd49..86b5e8c 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -396,7 +396,7 @@ void add_to_alternates_file(const char *reference)\n \t\tstruct strbuf line = STRBUF_INIT;\n \t\tint found = 0;\n \n-\t\twhile (strbuf_getline(&line, in, '\\n') != EOF) {\n+\t\twhile (strbuf_getline_lf(&line, in) != EOF) {\n \t\t\tif (!strcmp(reference, line.buf)) {\n \t\t\t\tfound = 1;\n \t\t\t\tbreak;\ndiff --git a/shell.c b/shell.c\nindex ace62e4..c5439a6 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -88,7 +88,7 @@ static void run_shell(void)\n \t\tint count;\n \n \t\tfprintf(stderr, \"git> \");\n-\t\tif (strbuf_getline(&line, stdin, '\\n') == EOF) {\n+\t\tif (strbuf_getline_lf(&line, stdin) == EOF) {\n \t\t\tfprintf(stderr, \"\\n\");\n \t\t\tstrbuf_release(&line);\n \t\t\tbreak;\ndiff --git a/strbuf.c b/strbuf.c\nindex 7ad5ea4..2ff898c 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -522,6 +522,16 @@ int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n \treturn 0;\n }\n \n+int strbuf_getline_lf(struct strbuf *sb, FILE *fp)\n+{\n+\treturn strbuf_getline(sb, fp, '\\n');\n+}\n+\n+int strbuf_getline_nul(struct strbuf *sb, FILE *fp)\n+{\n+\treturn strbuf_getline(sb, fp, '\\0');\n+}\n+\n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\n {\n \tstrbuf_reset(sb);\ndiff --git a/strbuf.h b/strbuf.h\nindex d84c866..5501743 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -388,6 +388,12 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  */\n extern int strbuf_getline(struct strbuf *, FILE *, int);\n \n+\n+typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n+\n+extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n+extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n+\n /*\n  * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n  * and additionally treats a '\\r' that comes immediately before '\\n'\n@@ -395,6 +401,7 @@ extern int strbuf_getline(struct strbuf *, FILE *, int);\n  */\n extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n \n+\n /**\n  * Like `strbuf_getline`, but keeps the trailing terminator (if\n  * any) in the buffer.\ndiff --git a/test-sha1-array.c b/test-sha1-array.c\nindex ddc491e..700f3f3 100644\n--- a/test-sha1-array.c\n+++ b/test-sha1-array.c\n@@ -11,7 +11,7 @@ int main(int argc, char **argv)\n \tstruct sha1_array array = SHA1_ARRAY_INIT;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline(&line, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline_lf(&line, stdin) != EOF) {\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n \ndiff --git a/transport-helper.c b/transport-helper.c\nindex 0eb3cf0..163e4b1 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)\n \tstrbuf_reset(buffer);\n \tif (debug)\n \t\tfprintf(stderr, \"Debug: Remote helper: Waiting...\\n\");\n-\tif (strbuf_getline(buffer, helper, '\\n') == EOF) {\n+\tif (strbuf_getline_lf(buffer, helper) == EOF) {\n \t\tif (debug)\n \t\t\tfprintf(stderr, \"Debug: Remote helper quit.\\n\");\n \t\treturn 1;\ndiff --git a/walker.c b/walker.c\nindex 7b7e72b..08773d4 100644\n--- a/walker.c\n+++ b/walker.c\n@@ -220,7 +220,7 @@ int walker_targets_stdin(char ***target, const char ***write_ref)\n \t\tchar *rf_one = NULL;\n \t\tchar *tg_one;\n \n-\t\tif (strbuf_getline(&buf, stdin, '\\n') == EOF)\n+\t\tif (strbuf_getline_lf(&buf, stdin) == EOF)\n \t\t\tbreak;\n \t\ttg_one = buf.buf;\n \t\trf_one = strchr(tg_one, '\\t');\ndiff --git a/wt-status.c b/wt-status.c\nindex bba2596..ab4f80d 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -988,7 +988,7 @@ static char *read_line_from_git_path(const char *filename)\n \t\tstrbuf_release(&buf);\n \t\treturn NULL;\n \t}\n-\tstrbuf_getline(&buf, fp, '\\n');\n+\tstrbuf_getline_lf(&buf, fp);\n \tif (!fclose(fp)) {\n \t\treturn strbuf_detach(&buf, NULL);\n \t} else {\n@@ -1076,7 +1076,7 @@ static void read_rebase_todolist(const char *fname, struct string_list *lines)\n \tif (!f)\n \t\tdie_errno(\"Could not open file %s for reading\",\n \t\t\t  git_path(\"%s\", fname));\n-\twhile (!strbuf_getline(&line, f, '\\n')) {\n+\twhile (!strbuf_getline_lf(&line, f)) {\n \t\tif (line.len && line.buf[0] == comment_line_char)\n \t\t\tcontinue;\n \t\tstrbuf_trim(&line);\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276097","messageId":"1452815916-6447-5-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 04/21] mktree: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:19Z","receivedAt":"2016-01-14T23:58:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default reads LF terminated lines, with an option to\nuse NUL terminated records.  Instead of pretending that there can be\nother useful values for line_termination, use a boolean variable,\nnul_term_line, to tell if NUL terminated records are used, and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/mktree.c | 14 ++++++++------\n 1 file changed, 8 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex a964d6b..a237caa 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -65,7 +65,7 @@ static const char *mktree_usage[] = {\n \tNULL\n };\n \n-static void mktree_line(char *buf, size_t len, int line_termination, int allow_missing)\n+static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_missing)\n {\n \tchar *ptr, *ntr;\n \tunsigned mode;\n@@ -97,7 +97,7 @@ static void mktree_line(char *buf, size_t len, int line_termination, int allow_m\n \t*ntr++ = 0; /* now at the beginning of SHA1 */\n \n \tpath = ntr + 41;  /* at the beginning of name */\n-\tif (line_termination && path[0] == '\"') {\n+\tif (!nul_term_line && path[0] == '\"') {\n \t\tstruct strbuf p_uq = STRBUF_INIT;\n \t\tif (unquote_c_style(&p_uq, path, NULL))\n \t\t\tdie(\"invalid quoting\");\n@@ -141,23 +141,25 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n \tunsigned char sha1[20];\n-\tint line_termination = '\\n';\n+\tint nul_term_line = 0;\n \tint allow_missing = 0;\n \tint is_batch_mode = 0;\n \tint got_eof = 0;\n+\tstrbuf_getline_fn getline_fn;\n \n \tconst struct option option[] = {\n-\t\tOPT_SET_INT('z', NULL, &line_termination, N_(\"input is NUL terminated\"), '\\0'),\n+\t\tOPT_BOOL('z', NULL, &nul_term_line, N_(\"input is NUL terminated\")),\n \t\tOPT_SET_INT( 0 , \"missing\", &allow_missing, N_(\"allow missing objects\"), 1),\n \t\tOPT_SET_INT( 0 , \"batch\", &is_batch_mode, N_(\"allow creation of more than one tree\"), 1),\n \t\tOPT_END()\n \t};\n \n \tac = parse_options(ac, av, prefix, option, mktree_usage, 0);\n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \n \twhile (!got_eof) {\n \t\twhile (1) {\n-\t\t\tif (strbuf_getline(&sb, stdin, line_termination) == EOF) {\n+\t\t\tif (getline_fn(&sb, stdin) == EOF) {\n \t\t\t\tgot_eof = 1;\n \t\t\t\tbreak;\n \t\t\t}\n@@ -167,7 +169,7 @@ int cmd_mktree(int ac, const char **av, const char *prefix)\n \t\t\t\t\tbreak;\n \t\t\t\tdie(\"input format error: (blank line only valid in batch mode)\");\n \t\t\t}\n-\t\t\tmktree_line(sb.buf, sb.len, line_termination, allow_missing);\n+\t\t\tmktree_line(sb.buf, sb.len, nul_term_line, allow_missing);\n \t\t}\n \t\tif (is_batch_mode && got_eof && used < 1) {\n \t\t\t/*\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276111","messageId":"1452815916-6447-6-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 05/21] check-attr: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:20Z","receivedAt":"2016-01-14T23:58:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default reads LF terminated lines, with an option to\nuse NUL terminated records.  Instead of pretending that there can be\nother useful values for line_termination, use a boolean variable,\nnul_term_line, to tell if NUL terminated records are used, and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/check-attr.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 265c9ba..087325e 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -73,12 +73,13 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n \tstruct git_attr_check *check)\n {\n \tstruct strbuf buf, nbuf;\n-\tint line_termination = nul_term_line ? 0 : '\\n';\n+\tstrbuf_getline_fn getline_fn;\n \n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n-\t\tif (line_termination && buf.buf[0] == '\"') {\n+\twhile (getline_fn(&buf, stdin) != EOF) {\n+\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276095","messageId":"1452815916-6447-7-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 06/21] check-ignore: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:21Z","receivedAt":"2016-01-14T23:58:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default reads LF terminated lines, with an option to\nuse NUL terminated records.  Instead of pretending that there can be\nother useful values for line_termination, use a boolean variable,\nnul_term_line, to tell if NUL terminated records are used, and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/check-ignore.c | 7 ++++---\n 1 file changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 43f3617..4f0b09e 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -117,13 +117,14 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n {\n \tstruct strbuf buf, nbuf;\n \tchar *pathspec[2] = { NULL, NULL };\n-\tint line_termination = nul_term_line ? 0 : '\\n';\n+\tstrbuf_getline_fn getline_fn;\n \tint num_ignored = 0;\n \n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \tstrbuf_init(&buf, 0);\n \tstrbuf_init(&nbuf, 0);\n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n-\t\tif (line_termination && buf.buf[0] == '\"') {\n+\twhile (getline_fn(&buf, stdin) != EOF) {\n+\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276096","messageId":"1452815916-6447-8-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 07/21] update-index: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:22Z","receivedAt":"2016-01-14T23:58:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default reads LF terminated lines, with an option to\nuse NUL terminated records.  Instead of pretending that there can be\nother useful values for line_termination, use a boolean variable,\nnul_term_line, to tell if NUL terminated records are used, and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/update-index.c | 27 ++++++++++++++++-----------\n 1 file changed, 16 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 7431938..7c5c143 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -468,12 +468,14 @@ static void update_one(const char *path)\n \treport(\"add '%s'\", path);\n }\n \n-static void read_index_info(int line_termination)\n+static void read_index_info(int nul_term_line)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf uq = STRBUF_INIT;\n+\tstrbuf_getline_fn getline_fn;\n \n-\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n+\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\tchar *ptr, *tab;\n \t\tchar *path_name;\n \t\tunsigned char sha1[20];\n@@ -522,7 +524,7 @@ static void read_index_info(int line_termination)\n \t\t\tgoto bad_line;\n \n \t\tpath_name = ptr;\n-\t\tif (line_termination && path_name[0] == '\"') {\n+\t\tif (!nul_term_line && path_name[0] == '\"') {\n \t\t\tstrbuf_reset(&uq);\n \t\t\tif (unquote_c_style(&uq, path_name, NULL)) {\n \t\t\t\tdie(\"git update-index: bad quoting of path name\");\n@@ -844,12 +846,12 @@ static int cacheinfo_callback(struct parse_opt_ctx_t *ctx,\n static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx,\n \t\t\t      const struct option *opt, int unset)\n {\n-\tint *line_termination = opt->value;\n+\tint *nul_term_line = opt->value;\n \n \tif (ctx->argc != 1)\n \t\treturn error(\"option '%s' must be the last argument\", opt->long_name);\n \tallow_add = allow_replace = allow_remove = 1;\n-\tread_index_info(*line_termination);\n+\tread_index_info(*nul_term_line);\n \treturn 0;\n }\n \n@@ -901,7 +903,7 @@ static int reupdate_callback(struct parse_opt_ctx_t *ctx,\n \n int cmd_update_index(int argc, const char **argv, const char *prefix)\n {\n-\tint newfd, entries, has_errors = 0, line_termination = '\\n';\n+\tint newfd, entries, has_errors = 0, nul_term_line = 0;\n \tint untracked_cache = -1;\n \tint read_from_stdin = 0;\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n@@ -912,6 +914,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \tint split_index = -1;\n \tstruct lock_file *lock_file;\n \tstruct parse_opt_ctx_t ctx;\n+\tstrbuf_getline_fn getline_fn;\n \tint parseopt_state = PARSE_OPT_UNKNOWN;\n \tstruct option options[] = {\n \t\tOPT_BIT('q', NULL, &refresh_args.flags,\n@@ -963,13 +966,13 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t\tN_(\"add to index only; do not add content to object database\"), 1),\n \t\tOPT_SET_INT(0, \"force-remove\", &force_remove,\n \t\t\tN_(\"remove named paths even if present in worktree\"), 1),\n-\t\tOPT_SET_INT('z', NULL, &line_termination,\n-\t\t\tN_(\"with --stdin: input lines are terminated by null bytes\"), '\\0'),\n+\t\tOPT_BOOL('z', NULL, &nul_term_line,\n+\t\t\t N_(\"with --stdin: input lines are terminated by null bytes\")),\n \t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"stdin\", &read_from_stdin, NULL,\n \t\t\tN_(\"read list of paths to be updated from standard input\"),\n \t\t\tPARSE_OPT_NONEG | PARSE_OPT_NOARG,\n \t\t\t(parse_opt_cb *) stdin_callback},\n-\t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"index-info\", &line_termination, NULL,\n+\t\t{OPTION_LOWLEVEL_CALLBACK, 0, \"index-info\", &nul_term_line, NULL,\n \t\t\tN_(\"add entries from standard input to the index\"),\n \t\t\tPARSE_OPT_NONEG | PARSE_OPT_NOARG,\n \t\t\t(parse_opt_cb *) stdin_cacheinfo_callback},\n@@ -1057,6 +1060,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \targc = parse_options_end(&ctx);\n+\n+\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n \tif (preferred_index_format) {\n \t\tif (preferred_index_format < INDEX_FORMAT_LB ||\n \t\t    INDEX_FORMAT_UB < preferred_index_format)\n@@ -1073,9 +1078,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n \t\tsetup_work_tree();\n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\t\tchar *p;\n-\t\t\tif (line_termination && buf.buf[0] == '\"') {\n+\t\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n \t\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276093","messageId":"1452815916-6447-9-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 08/21] checkout-index: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:23Z","receivedAt":"2016-01-14T23:58:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The program by default reads LF terminated lines, with an option to\nuse NUL terminated records.  Instead of pretending that there can be\nother useful values for line_termination, use a boolean variable,\nnul_term_line, to tell if NUL terminated records are used, and\nswitch between strbuf_getline_{lf,nul} based on it.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/checkout-index.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex 8028c37..ed888a5 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -11,7 +11,7 @@\n #include \"parse-options.h\"\n \n #define CHECKOUT_ALL 4\n-static int line_termination = '\\n';\n+static int nul_term_line;\n static int checkout_stage; /* default to checkout stage0 */\n static int to_tempfile;\n static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];\n@@ -35,7 +35,8 @@ static void write_tempfile_record(const char *name, const char *prefix)\n \t\tfputs(topath[checkout_stage], stdout);\n \n \tputchar('\\t');\n-\twrite_name_quoted_relative(name, prefix, stdout, line_termination);\n+\twrite_name_quoted_relative(name, prefix, stdout,\n+\t\t\t\t   nul_term_line ? '\\0' : '\\n');\n \n \tfor (i = 0; i < 4; i++) {\n \t\ttopath[i][0] = 0;\n@@ -144,10 +145,7 @@ static int option_parse_u(const struct option *opt,\n static int option_parse_z(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n-\tif (unset)\n-\t\tline_termination = '\\n';\n-\telse\n-\t\tline_termination = 0;\n+\tnul_term_line = !unset;\n \treturn 0;\n }\n \n@@ -254,13 +252,15 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \n \tif (read_from_stdin) {\n \t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n+\t\tstrbuf_getline_fn getline_fn;\n \n \t\tif (all)\n \t\t\tdie(\"git checkout-index: don't mix '--all' and '--stdin'\");\n \n-\t\twhile (strbuf_getline(&buf, stdin, line_termination) != EOF) {\n+\t\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n+\t\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\t\tchar *p;\n-\t\t\tif (line_termination && buf.buf[0] == '\"') {\n+\t\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n \t\t\t\tstrbuf_reset(&nbuf);\n \t\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n \t\t\t\t\tdie(\"line is badly quoted\");\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276098","messageId":"1452815916-6447-10-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 09/21] strbuf: give strbuf_getline() to the \"most text friendly\" variant","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:24Z","receivedAt":"2016-01-14T23:58:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Now there is no direct caller to strbuf_getline(), we can demote it\nto file-scope static private to strbuf.c implementation and rename\nit to strbuf_getdelim().  Rename strbuf_getline_crlf(), which is\ndesigned to be the most \"text friendly\" variant, and allow it to\ntake over this simplest name, strbuf_getline(), so we can add more\nuses of it without having to type _crlf over and over again in the\ncoming steps.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/am.c       |  8 ++++----\n strbuf.c           |  8 ++++----\n strbuf.h           | 25 ++++++++++++++-----------\n transport-helper.c |  3 ++-\n 4 files changed, 24 insertions(+), 20 deletions(-)\n\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 9063a4a..7b8351d 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -613,7 +613,7 @@ static int is_mail(FILE *fp)\n \tif (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))\n \t\tdie(\"invalid pattern: %s\", header_regex);\n \n-\twhile (!strbuf_getline_crlf(&sb, fp)) {\n+\twhile (!strbuf_getline(&sb, fp)) {\n \t\tif (!sb.len)\n \t\t\tbreak; /* End of header */\n \n@@ -660,7 +660,7 @@ static int detect_patch_format(const char **paths)\n \n \tfp = xfopen(*paths, \"r\");\n \n-\twhile (!strbuf_getline_crlf(&l1, fp)) {\n+\twhile (!strbuf_getline(&l1, fp)) {\n \t\tif (l1.len)\n \t\t\tbreak;\n \t}\n@@ -681,9 +681,9 @@ static int detect_patch_format(const char **paths)\n \t}\n \n \tstrbuf_reset(&l2);\n-\tstrbuf_getline_crlf(&l2, fp);\n+\tstrbuf_getline(&l2, fp);\n \tstrbuf_reset(&l3);\n-\tstrbuf_getline_crlf(&l3, fp);\n+\tstrbuf_getline(&l3, fp);\n \n \t/*\n \t * If the second line is empty and the third is a From, Author or Date\ndiff --git a/strbuf.c b/strbuf.c\nindex 2ff898c..47ac045 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -501,7 +501,7 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)\n }\n #endif\n \n-int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n+static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)\n {\n \tif (strbuf_getwholeline(sb, fp, term))\n \t\treturn EOF;\n@@ -510,7 +510,7 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)\n \treturn 0;\n }\n \n-int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n+int strbuf_getline(struct strbuf *sb, FILE *fp)\n {\n \tif (strbuf_getwholeline(sb, fp, '\\n'))\n \t\treturn EOF;\n@@ -524,12 +524,12 @@ int strbuf_getline_crlf(struct strbuf *sb, FILE *fp)\n \n int strbuf_getline_lf(struct strbuf *sb, FILE *fp)\n {\n-\treturn strbuf_getline(sb, fp, '\\n');\n+\treturn strbuf_getdelim(sb, fp, '\\n');\n }\n \n int strbuf_getline_nul(struct strbuf *sb, FILE *fp)\n {\n-\treturn strbuf_getline(sb, fp, '\\0');\n+\treturn strbuf_getdelim(sb, fp, '\\0');\n }\n \n int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)\ndiff --git a/strbuf.h b/strbuf.h\nindex 5501743..220c541 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -354,8 +354,8 @@ extern void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm\n  *\n  * NOTE: The buffer is rewound if the read fails. If -1 is returned,\n  * `errno` must be consulted, like you would do for `read(3)`.\n- * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the\n- * same behaviour as well.\n+ * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline_*()`\n+ * family of functions have the same behaviour as well.\n  */\n extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);\n \n@@ -380,26 +380,29 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n \n /**\n  * Read a line from a FILE *, overwriting the existing contents\n- * of the strbuf. The second argument specifies the line\n- * terminator character, typically `'\\n'`.\n+ * of the strbuf.  There are three public functions with this\n+ * function signature, with different line termination convention.\n  * Reading stops after the terminator or at EOF.  The terminator\n  * is removed from the buffer before returning.  Returns 0 unless\n  * there was nothing left before EOF, in which case it returns `EOF`.\n  */\n-extern int strbuf_getline(struct strbuf *, FILE *, int);\n-\n \n typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n \n+/* Uses LF as the line terminator */\n extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n+\n+/* Uses NUL as the line terminator */\n extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n \n-/*\n- * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n- * and additionally treats a '\\r' that comes immediately before '\\n'\n- * as part of the terminator.\n+/**\n+ * Similar to strbuf_getline_lf(), but additionally treats\n+ * a '\\r' that comes immediately before '\\n' as part of the\n+ * terminator.  This is the most friendly version to be used\n+ * to read \"text\" files that can come from platforms whose\n+ * native text format is CRLF terminated.\n  */\n-extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n+extern int strbuf_getline(struct strbuf *, FILE *);\n \n \n /**\ndiff --git a/transport-helper.c b/transport-helper.c\nindex 163e4b1..e45d88f 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -137,7 +137,8 @@ static struct child_process *get_helper(struct transport *transport)\n \tdata->no_disconnect_req = 0;\n \n \t/*\n-\t * Open the output as FILE* so strbuf_getline() can be used.\n+\t * Open the output as FILE* so strbuf_getline_*() family of\n+\t * functions can be used.\n \t * Do this with duped fd because fclose() will close the fd,\n \t * and stuff like taking over will require the fd to remain.\n \t */\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276108","messageId":"1452815916-6447-11-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 10/21] hash-object: read --stdin-paths with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:25Z","receivedAt":"2016-01-14T23:58:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The list of paths could have been written with a DOS editor.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/hash-object.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 3bc5ec1..ff20395 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n {\n \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n \n-\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n+\twhile (strbuf_getline(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&nbuf);\n \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276112","messageId":"1452815916-6447-12-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 11/21] revision: read --stdin with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:26Z","receivedAt":"2016-01-14T23:58:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Reading with getwholeline() and manually stripping the terminating\n'\\n' would leave CR at the end of the line if the input comes from\na DOS editor.\n\nConstrasting this with the previous few changes, one may realize\nthat the way \"log\" family of commands read the paths with --stdin\nlooks inconsistent and sloppy.  It does not allow us to C-quote a\ntextual input, and it does not accept NUL-terminated records.  These\nare unfortunately way too late to fix X-<.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c | 9 ++-------\n 1 file changed, 2 insertions(+), 7 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex 0a282f5..8df4e11 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1635,10 +1635,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av)\n static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n \t\t\t\t     struct cmdline_pathspec *prune)\n {\n-\twhile (strbuf_getwholeline(sb, stdin, '\\n') != EOF) {\n-\t\tint len = sb->len;\n-\t\tif (len && sb->buf[len - 1] == '\\n')\n-\t\t\tsb->buf[--len] = '\\0';\n+\twhile (strbuf_getline(sb, stdin) != EOF) {\n \t\tALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n \t\tprune->path[prune->nr++] = xstrdup(sb->buf);\n \t}\n@@ -1655,10 +1652,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \twarn_on_object_refname_ambiguity = 0;\n \n \tstrbuf_init(&sb, 1000);\n-\twhile (strbuf_getwholeline(&sb, stdin, '\\n') != EOF) {\n+\twhile (strbuf_getline(&sb, stdin) != EOF) {\n \t\tint len = sb.len;\n-\t\tif (len && sb.buf[len - 1] == '\\n')\n-\t\t\tsb.buf[--len] = '\\0';\n \t\tif (!len)\n \t\t\tbreak;\n \t\tif (sb.buf[0] == '-') {\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276110","messageId":"1452815916-6447-13-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 12/21] rev-parse: read parseopt spec with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:27Z","receivedAt":"2016-01-14T23:58:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"rev-parse --parseopt\" specification is clearly text and we\nshould anticipate that we may be fed CRLF lines.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/rev-parse.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 0324abb..bd16876 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -383,7 +383,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \n \t/* get the usage up to the first line with a -- on it */\n \tfor (;;) {\n-\t\tif (strbuf_getline_lf(&sb, stdin) == EOF)\n+\t\tif (strbuf_getline(&sb, stdin) == EOF)\n \t\t\tdie(\"premature end of input\");\n \t\tALLOC_GROW(usage, unb + 1, usz);\n \t\tif (!strcmp(\"--\", sb.buf)) {\n@@ -396,7 +396,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)\n \t}\n \n \t/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */\n-\twhile (strbuf_getline_lf(&sb, stdin) != EOF) {\n+\twhile (strbuf_getline(&sb, stdin) != EOF) {\n \t\tconst char *s;\n \t\tconst char *help;\n \t\tstruct option *o;\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276099","messageId":"1452815916-6447-14-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 13/21] ident.c: read /etc/mailname with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:28Z","receivedAt":"2016-01-14T23:58:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Just in case /etc/mailname file was edited with a DOS editor,\nread it with strbuf_getline() so that a stray CR is not included\nas the last character of the mail hostname.\n\nWe _might_ want to more aggressively discard whitespace characters\naround the line with strbuf_trim(), but that is a bit outside the\nscope of this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n ident.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/ident.c b/ident.c\nindex 9dd3ae3..3da5556 100644\n--- a/ident.c\n+++ b/ident.c\n@@ -76,7 +76,7 @@ static int add_mailname_host(struct strbuf *buf)\n \t\t\t\tstrerror(errno));\n \t\treturn -1;\n \t}\n-\tif (strbuf_getline_lf(&mailnamebuf, mailname) == EOF) {\n+\tif (strbuf_getline(&mailnamebuf, mailname) == EOF) {\n \t\tif (ferror(mailname))\n \t\t\twarning(\"cannot read /etc/mailname: %s\",\n \t\t\t\tstrerror(errno));\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276100","messageId":"1452815916-6447-15-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 14/21] remote.c: read $GIT_DIR/remotes/* with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:29Z","receivedAt":"2016-01-14T23:58:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These files can be edited with a DOS editor, leaving CR at the end\nof the line if read with strbuf_getline().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/remote.c b/remote.c\nindex f195693..7d61dab 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -256,7 +256,7 @@ static void read_remotes_file(struct remote *remote)\n \tif (!f)\n \t\treturn;\n \tremote->origin = REMOTE_REMOTES;\n-\twhile (strbuf_getline_lf(&buf, f) != EOF) {\n+\twhile (strbuf_getline(&buf, f) != EOF) {\n \t\tconst char *v;\n \n \t\tstrbuf_rtrim(&buf);\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276103","messageId":"1452815916-6447-16-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 15/21] clone/sha1_file: read info/alternates with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:30Z","receivedAt":"2016-01-14T23:58:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"$GIT_OBJECT_DIRECTORY/info/alternates is a text file that can be\nedited with a DOS editor.  We do not want to use the real path with\nCR appeneded at the end.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/clone.c | 2 +-\n sha1_file.c     | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/clone.c b/builtin/clone.c\nindex 29741f4..43b4c99 100644\n--- a/builtin/clone.c\n+++ b/builtin/clone.c\n@@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n \tFILE *in = fopen(src->buf, \"r\");\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline_lf(&line, in) != EOF) {\n+\twhile (strbuf_getline(&line, in) != EOF) {\n \t\tchar *abs_path;\n \t\tif (!line.len || line.buf[0] == '#')\n \t\t\tcontinue;\ndiff --git a/sha1_file.c b/sha1_file.c\nindex 86b5e8c..aab1872 100644\n--- a/sha1_file.c\n+++ b/sha1_file.c\n@@ -396,7 +396,7 @@ void add_to_alternates_file(const char *reference)\n \t\tstruct strbuf line = STRBUF_INIT;\n \t\tint found = 0;\n \n-\t\twhile (strbuf_getline_lf(&line, in) != EOF) {\n+\t\twhile (strbuf_getline(&line, in) != EOF) {\n \t\t\tif (!strcmp(reference, line.buf)) {\n \t\t\t\tfound = 1;\n \t\t\t\tbreak;\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276107","messageId":"1452815916-6447-17-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 16/21] transport-helper: read helper response with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:31Z","receivedAt":"2016-01-14T23:58:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Our implementation of helpers never use CRLF line endings, and they\ndo not depend on the ability to place a CR as payload at the end of\nthe line, so this is essentially a no-op for in-tree users.  However,\nthis allows third-party implementation of helpers to give us their\nline with CRLF line ending (they cannot expect us to feed CRLF to\nthem, though).\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n transport-helper.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/transport-helper.c b/transport-helper.c\nindex e45d88f..a6bff8b 100644\n--- a/transport-helper.c\n+++ b/transport-helper.c\n@@ -54,7 +54,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name)\n \tstrbuf_reset(buffer);\n \tif (debug)\n \t\tfprintf(stderr, \"Debug: Remote helper: Waiting...\\n\");\n-\tif (strbuf_getline_lf(buffer, helper) == EOF) {\n+\tif (strbuf_getline(buffer, helper) == EOF) {\n \t\tif (debug)\n \t\t\tfprintf(stderr, \"Debug: Remote helper quit.\\n\");\n \t\treturn 1;\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276102","messageId":"1452815916-6447-18-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 17/21] cat-file: read batch stream with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:32Z","receivedAt":"2016-01-14T23:58:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"It is possible to prepare a text file with a DOS editor and feed it\nas a batch command stream to the command.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/cat-file.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex d2ebaf1..54db118 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n \tsave_warning = warn_on_object_refname_ambiguity;\n \twarn_on_object_refname_ambiguity = 0;\n \n-\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n+\twhile (strbuf_getline(&buf, stdin) != EOF) {\n \t\tif (data.split_on_whitespace) {\n \t\t\t/*\n \t\t\t * Split at first whitespace, tying off the beginning\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276106","messageId":"1452815916-6447-19-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 18/21] column: read lines with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:33Z","receivedAt":"2016-01-14T23:58:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Multiple lines read here are concatenated on a single line to form a\nmulti-column output line.  We do not want to have a CR at the end,\neven if the input file consists of CRLF terminated lines.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/column.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/column.c b/builtin/column.c\nindex 40eab08..33314b4 100644\n--- a/builtin/column.c\n+++ b/builtin/column.c\n@@ -51,7 +51,7 @@ int cmd_column(int argc, const char **argv, const char *prefix)\n \t\t\tdie(_(\"--command must be the first argument\"));\n \t}\n \tfinalize_colopts(&colopts, -1);\n-\twhile (!strbuf_getline_lf(&sb, stdin))\n+\twhile (!strbuf_getline(&sb, stdin))\n \t\tstring_list_append(&list, sb.buf);\n \n \tprint_columns(&list, colopts, &copts);\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276101","messageId":"1452815916-6447-20-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 19/21] send-pack: read list of refs with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:34Z","receivedAt":"2016-01-14T23:58:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/send-pack.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/send-pack.c b/builtin/send-pack.c\nindex 8f9f4f1..5b9dd6a 100644\n--- a/builtin/send-pack.c\n+++ b/builtin/send-pack.c\n@@ -212,7 +212,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)\n \t\t\t\targv_array_push(&all_refspecs, buf);\n \t\t} else {\n \t\t\tstruct strbuf line = STRBUF_INIT;\n-\t\t\twhile (strbuf_getline_lf(&line, stdin) != EOF)\n+\t\t\twhile (strbuf_getline(&line, stdin) != EOF)\n \t\t\t\targv_array_push(&all_refspecs, line.buf);\n \t\t\tstrbuf_release(&line);\n \t\t}\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276104","messageId":"1452815916-6447-21-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 20/21] grep: read -f file with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:35Z","receivedAt":"2016-01-14T23:58:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"List of patterns file could come from a DOS editor.\n\nThis is iffy; you may actually be trying to find a line with ^M in\nit on a system whose line ending is LF.  You can of course work it\naround by having a line that has \"^M^M^J\", let the strbuf_getline()\neat the last \"^M^J\", leaving just the single \"^M\" as the pattern.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/grep.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5a5beb8..801ce60 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -562,7 +562,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset)\n \tpatterns = from_stdin ? stdin : fopen(arg, \"r\");\n \tif (!patterns)\n \t\tdie_errno(_(\"cannot open '%s'\"), arg);\n-\twhile (strbuf_getline_lf(&sb, patterns) == 0) {\n+\twhile (strbuf_getline(&sb, patterns) == 0) {\n \t\t/* ignore empty line like grep does */\n \t\tif (sb.len == 0)\n \t\t\tcontinue;\n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276105","messageId":"1452815916-6447-22-git-send-email-gitster@pobox.com","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"[PATCH v4 21/21] test-sha1-array: read command stream with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-14T23:58:36Z","receivedAt":"2016-01-14T23:58:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The input to this command comes from a pipeline in t0064, whose\nupstream has bunch of \"echo\"s.  It is not unreasonable to expect\nthat it may be fed CRLF lines on DOSsy systems.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n test-sha1-array.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/test-sha1-array.c b/test-sha1-array.c\nindex 700f3f3..60ea1d5 100644\n--- a/test-sha1-array.c\n+++ b/test-sha1-array.c\n@@ -11,7 +11,7 @@ int main(int argc, char **argv)\n \tstruct sha1_array array = SHA1_ARRAY_INIT;\n \tstruct strbuf line = STRBUF_INIT;\n \n-\twhile (strbuf_getline_lf(&line, stdin) != EOF) {\n+\twhile (strbuf_getline(&line, stdin) != EOF) {\n \t\tconst char *arg;\n \t\tunsigned char sha1[20];\n \n-- \n2.7.0-250-ge1b5ba3\n"},{"id":"276119","messageId":"CAPig+cSAO-bJTvkOO-h=R-FKE90pfiJAaW-n-9Gi-omEr7aMCQ@mail.gmail.com","threadId":"40059","inReplyTo":"1452815916-6447-10-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 09/21] strbuf: give strbuf_getline() to the \"most text friendly\" variant","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-01-15T01:46:47Z","receivedAt":"2016-01-15T01:46:47Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jan 14, 2016 at 6:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Now there is no direct caller to strbuf_getline(), we can demote it\n> to file-scope static private to strbuf.c implementation and rename\n> it to strbuf_getdelim().  Rename strbuf_getline_crlf(), which is\n> designed to be the most \"text friendly\" variant, and allow it to\n> take over this simplest name, strbuf_getline(), so we can add more\n> uses of it without having to type _crlf over and over again in the\n> coming steps.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> diff --git a/strbuf.h b/strbuf.h\n> @@ -380,26 +380,29 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n>\n>  /**\n>   * Read a line from a FILE *, overwriting the existing contents\n> - * of the strbuf. The second argument specifies the line\n> - * terminator character, typically `'\\n'`.\n> + * of the strbuf.  There are three public functions with this\n> + * function signature, with different line termination convention.\n\ns/public// perhaps?\n\nAlso, is it worth worrying that the comment may become outdated due to\nthe mentioned \"three\"? Perhaps s/three/several/? Or:\n\n    The family of strbuf_getline*() functions share the same\n    signature, but have different line termination conventions.\n\n>   * Reading stops after the terminator or at EOF.  The terminator\n>   * is removed from the buffer before returning.  Returns 0 unless\n>   * there was nothing left before EOF, in which case it returns `EOF`.\n>   */\n> -extern int strbuf_getline(struct strbuf *, FILE *, int);\n> -\n>\n>  typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n>\n> +/* Uses LF as the line terminator */\n>  extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n> +\n> +/* Uses NUL as the line terminator */\n>  extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n\nThis documentation could have been included in patch 3/21.\n\n> -/*\n> - * Similar to strbuf_getline(), but uses '\\n' as the terminator,\n> - * and additionally treats a '\\r' that comes immediately before '\\n'\n> - * as part of the terminator.\n> +/**\n> + * Similar to strbuf_getline_lf(), but additionally treats\n> + * a '\\r' that comes immediately before '\\n' as part of the\n> + * terminator.  This is the most friendly version to be used\n> + * to read \"text\" files that can come from platforms whose\n> + * native text format is CRLF terminated.\n>   */\n> -extern int strbuf_getline_crlf(struct strbuf *, FILE *);\n> +extern int strbuf_getline(struct strbuf *, FILE *);\n"},{"id":"276120","messageId":"CAPig+cRJEUB-Fsage2G85g1s_TxSLbAmtDVqu8VDaNpBRWLkcQ@mail.gmail.com","threadId":"40059","inReplyTo":"1452815916-6447-12-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 11/21] revision: read --stdin with strbuf_getline()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-01-15T01:50:36Z","receivedAt":"2016-01-15T01:50:36Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jan 14, 2016 at 6:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Reading with getwholeline() and manually stripping the terminating\n> '\\n' would leave CR at the end of the line if the input comes from\n> a DOS editor.\n>\n> Constrasting this with the previous few changes, one may realize\n\nTo what does \"Contrasting this with the previous few changes\" refer?\nDid this patch previously come later in the series, or am I missing\nsomething obvious?\n\n> that the way \"log\" family of commands read the paths with --stdin\n> looks inconsistent and sloppy.  It does not allow us to C-quote a\n> textual input, and it does not accept NUL-terminated records.  These\n> are unfortunately way too late to fix X-<.\n>\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  revision.c | 9 ++-------\n>  1 file changed, 2 insertions(+), 7 deletions(-)\n>\n> diff --git a/revision.c b/revision.c\n> index 0a282f5..8df4e11 100644\n> --- a/revision.c\n> +++ b/revision.c\n> @@ -1635,10 +1635,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av)\n>  static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n>                                      struct cmdline_pathspec *prune)\n>  {\n> -       while (strbuf_getwholeline(sb, stdin, '\\n') != EOF) {\n> -               int len = sb->len;\n> -               if (len && sb->buf[len - 1] == '\\n')\n> -                       sb->buf[--len] = '\\0';\n> +       while (strbuf_getline(sb, stdin) != EOF) {\n>                 ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n>                 prune->path[prune->nr++] = xstrdup(sb->buf);\n>         }\n> @@ -1655,10 +1652,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n>         warn_on_object_refname_ambiguity = 0;\n>\n>         strbuf_init(&sb, 1000);\n> -       while (strbuf_getwholeline(&sb, stdin, '\\n') != EOF) {\n> +       while (strbuf_getline(&sb, stdin) != EOF) {\n>                 int len = sb.len;\n> -               if (len && sb.buf[len - 1] == '\\n')\n> -                       sb.buf[--len] = '\\0';\n>                 if (!len)\n>                         break;\n>                 if (sb.buf[0] == '-') {\n> --\n> 2.7.0-250-ge1b5ba3\n"},{"id":"276121","messageId":"CAPig+cSoi3S5HJVyVW4-qs8BsZ7E5iF_cq5Z3zJiMgk4O4LvZg@mail.gmail.com","threadId":"40059","inReplyTo":"1452815916-6447-16-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 15/21] clone/sha1_file: read info/alternates with strbuf_getline()","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2016-01-15T01:52:49Z","receivedAt":"2016-01-15T01:52:49Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jan 14, 2016 at 6:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> $GIT_OBJECT_DIRECTORY/info/alternates is a text file that can be\n> edited with a DOS editor.  We do not want to use the real path with\n> CR appeneded at the end.\n\ns/appeneded/appended/\n\n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> diff --git a/builtin/clone.c b/builtin/clone.c\n> index 29741f4..43b4c99 100644\n> --- a/builtin/clone.c\n> +++ b/builtin/clone.c\n> @@ -339,7 +339,7 @@ static void copy_alternates(struct strbuf *src, struct strbuf *dst,\n>         FILE *in = fopen(src->buf, \"r\");\n>         struct strbuf line = STRBUF_INIT;\n>\n> -       while (strbuf_getline_lf(&line, in) != EOF) {\n> +       while (strbuf_getline(&line, in) != EOF) {\n>                 char *abs_path;\n>                 if (!line.len || line.buf[0] == '#')\n>                         continue;\n> diff --git a/sha1_file.c b/sha1_file.c\n> index 86b5e8c..aab1872 100644\n> --- a/sha1_file.c\n> +++ b/sha1_file.c\n> @@ -396,7 +396,7 @@ void add_to_alternates_file(const char *reference)\n>                 struct strbuf line = STRBUF_INIT;\n>                 int found = 0;\n>\n> -               while (strbuf_getline_lf(&line, in) != EOF) {\n> +               while (strbuf_getline(&line, in) != EOF) {\n>                         if (!strcmp(reference, line.buf)) {\n>                                 found = 1;\n>                                 break;\n> --\n> 2.7.0-250-ge1b5ba3\n"},{"id":"276180","messageId":"xmqqoacmiuvy.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"CAPig+cSAO-bJTvkOO-h=R-FKE90pfiJAaW-n-9Gi-omEr7aMCQ@mail.gmail.com","subject":"Re: [PATCH v4 09/21] strbuf: give strbuf_getline() to the \"most text friendly\" variant","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-15T18:02:09Z","receivedAt":"2016-01-15T18:02:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n>>  /**\n>>   * Read a line from a FILE *, overwriting the existing contents\n>> - * of the strbuf. The second argument specifies the line\n>> - * terminator character, typically `'\\n'`.\n>> + * of the strbuf.  There are three public functions with this\n>> + * function signature, with different line termination convention.\n>\n> s/public// perhaps?\n>\n> Also, is it worth worrying that the comment may become outdated due to\n> the mentioned \"three\"? Perhaps s/three/several/? Or:\n>\n>     The family of strbuf_getline*() functions share the same\n>     signature, but have different line termination conventions.\n\nI like this one the best, and that is not because I foresee \"three\"\nto be changing (strbuf_getdelim() could become public again, but it\nhas a different signature), but because it is concise and to the\npoint.\n\n>>   * Reading stops after the terminator or at EOF.  The terminator\n>>   * is removed from the buffer before returning.  Returns 0 unless\n>>   * there was nothing left before EOF, in which case it returns `EOF`.\n>>   */\n>> -extern int strbuf_getline(struct strbuf *, FILE *, int);\n>> -\n>>\n>>  typedef int (*strbuf_getline_fn)(struct strbuf *, FILE *);\n>>\n>> +/* Uses LF as the line terminator */\n>>  extern int strbuf_getline_lf(struct strbuf *sb, FILE *fp);\n>> +\n>> +/* Uses NUL as the line terminator */\n>>  extern int strbuf_getline_nul(struct strbuf *sb, FILE *fp);\n>\n> This documentation could have been included in patch 3/21.\n\nPerhaps.  I'll see what the best tweak would be.\n\nThanks.\n"},{"id":"276183","messageId":"xmqqk2nait84.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"CAPig+cRJEUB-Fsage2G85g1s_TxSLbAmtDVqu8VDaNpBRWLkcQ@mail.gmail.com","subject":"Re: [PATCH v4 11/21] revision: read --stdin with strbuf_getline()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-15T18:38:03Z","receivedAt":"2016-01-15T18:38:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Thu, Jan 14, 2016 at 6:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Reading with getwholeline() and manually stripping the terminating\n>> '\\n' would leave CR at the end of the line if the input comes from\n>> a DOS editor.\n>>\n>> Constrasting this with the previous few changes, one may realize\n>\n> To what does \"Contrasting this with the previous few changes\" refer?\n> Did this patch previously come later in the series, or am I missing\n> something obvious?\n\nPerhaps that is what happened.  It was meant to ask the readers to\ncompare the handling of \"--stdin\" by the log family of functions\n(done by code in revision.c here) with other codepaths.\n\nWill reword.  Thanks.\n\n>\n>> that the way \"log\" family of commands read the paths with --stdin\n>> looks inconsistent and sloppy.  It does not allow us to C-quote a\n>> textual input, and it does not accept NUL-terminated records.  These\n>> are unfortunately way too late to fix X-<.\n>>\n>> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n>> ---\n>>  revision.c | 9 ++-------\n>>  1 file changed, 2 insertions(+), 7 deletions(-)\n>>\n>> diff --git a/revision.c b/revision.c\n>> index 0a282f5..8df4e11 100644\n>> --- a/revision.c\n>> +++ b/revision.c\n>> @@ -1635,10 +1635,7 @@ static void append_prune_data(struct cmdline_pathspec *prune, const char **av)\n>>  static void read_pathspec_from_stdin(struct rev_info *revs, struct strbuf *sb,\n>>                                      struct cmdline_pathspec *prune)\n>>  {\n>> -       while (strbuf_getwholeline(sb, stdin, '\\n') != EOF) {\n>> -               int len = sb->len;\n>> -               if (len && sb->buf[len - 1] == '\\n')\n>> -                       sb->buf[--len] = '\\0';\n>> +       while (strbuf_getline(sb, stdin) != EOF) {\n>>                 ALLOC_GROW(prune->path, prune->nr + 1, prune->alloc);\n>>                 prune->path[prune->nr++] = xstrdup(sb->buf);\n>>         }\n>> @@ -1655,10 +1652,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n>>         warn_on_object_refname_ambiguity = 0;\n>>\n>>         strbuf_init(&sb, 1000);\n>> -       while (strbuf_getwholeline(&sb, stdin, '\\n') != EOF) {\n>> +       while (strbuf_getline(&sb, stdin) != EOF) {\n>>                 int len = sb.len;\n>> -               if (len && sb.buf[len - 1] == '\\n')\n>> -                       sb.buf[--len] = '\\0';\n>>                 if (!len)\n>>                         break;\n>>                 if (sb.buf[0] == '-') {\n>> --\n>> 2.7.0-250-ge1b5ba3\n"},{"id":"276188","messageId":"20160115191051.GA11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 00/21] Peace with CRLF","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T19:10:51Z","receivedAt":"2016-01-15T19:10:51Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:15PM -0800, Junio C Hamano wrote:\n\n>  - The update to mktree used \"lf_lines\" in the preview, but this\n>    version flips it to the same \"nul_term_line\" to match other two,\n>    even though I think the latter is a terrible variable name with\n>    bad taste.\n\nHeh. I also dislike that variable name, but not want to nit-pick when\nreading the preview.\n\nI think just \"use_nul_terminator\" or something would be fine. It is\nreally the \"line\" which bugs me, because they are not really lines\nanymore.\n\n-Peff\n"},{"id":"276189","messageId":"20160115191611.GB11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-6-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 05/21] check-attr: there are only two possible line terminations","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T19:16:11Z","receivedAt":"2016-01-15T19:16:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:20PM -0800, Junio C Hamano wrote:\n\n> The program by default reads LF terminated lines, with an option to\n> use NUL terminated records.  Instead of pretending that there can be\n> other useful values for line_termination, use a boolean variable,\n> nul_term_line, to tell if NUL terminated records are used, and\n> switch between strbuf_getline_{lf,nul} based on it.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/check-attr.c | 7 ++++---\n>  1 file changed, 4 insertions(+), 3 deletions(-)\n> \n> diff --git a/builtin/check-attr.c b/builtin/check-attr.c\n> index 265c9ba..087325e 100644\n> --- a/builtin/check-attr.c\n> +++ b/builtin/check-attr.c\n> @@ -73,12 +73,13 @@ static void check_attr_stdin_paths(const char *prefix, int cnt,\n>  \tstruct git_attr_check *check)\n>  {\n>  \tstruct strbuf buf, nbuf;\n> -\tint line_termination = nul_term_line ? 0 : '\\n';\n> +\tstrbuf_getline_fn getline_fn;\n>  \n> +\tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n>  \tstrbuf_init(&buf, 0);\n>  \tstrbuf_init(&nbuf, 0);\n\nNot really relevant to your series, but I find it slightly confusing\nwhen `strbuf_init` is used instead of a static initializer (it makes me\nwonder _why_, and whether there are any code paths that miss\ninitialization).\n\nMaybe worth doing:\n\n  struct strbuf buf = STRBUF_INIT;\n  struct strbuf nbuf = STRBUF_INIT;\n\nat the top while we are in the area (and also maybe giving the latter a\nmore meaningful name!).  But I don't want to derail the main point of\nyour series.\n\n-Peff\n"},{"id":"276190","messageId":"20160115193640.GA19291@sigill.intra.peff.net","threadId":"40059","inReplyTo":"20160115191611.GB11301@sigill.intra.peff.net","subject":"Re: [PATCH v4 05/21] check-attr: there are only two possible line terminations","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T19:36:40Z","receivedAt":"2016-01-15T19:36:40Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 15, 2016 at 02:16:11PM -0500, Jeff King wrote:\n\n> Not really relevant to your series, but I find it slightly confusing\n> when `strbuf_init` is used instead of a static initializer (it makes me\n> wonder _why_, and whether there are any code paths that miss\n> initialization).\n> \n> Maybe worth doing:\n> \n>   struct strbuf buf = STRBUF_INIT;\n>   struct strbuf nbuf = STRBUF_INIT;\n> \n> at the top while we are in the area (and also maybe giving the latter a\n> more meaningful name!).  But I don't want to derail the main point of\n> your series.\n\nApparently we use this pattern in quite a few places (or they all copied\nfrom each other). Here's a possible fixup that could go after your\nseries (it could go before, too, but it creates a lot of textual\nconflicts with your stuff).\n\n-- >8 --\nSubject: [PATCH] give \"nbuf\" strbuf a more meaningful name\n\nIt's a common pattern in our code to read paths from stdin,\nseparated either by newlines or NULs, and unquote as\nnecessary. In each of these five cases we use \"nbuf\" to\ntemporarily store the unquoted value. Let's give it the more\nmeaningful name \"unquoted\", which makes it easier to\nunderstand the purpose of the variable.\n\nWhile we're at it, let's also static-initialize all of our\nstrbufs. It's not wrong to call strbuf_init, but it\nincreases the cognitive load on the reader (who might wonder\n\"do we sometimes avoid initializing them? why?\").\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nIt's a shame that we can't just factor out this common code, but I don't\nthink it's quite long enough to merit the boilerplate. The interesting\npart of each function happens inside the loop. If C had lambdas, we\ncould do something like:\n\n  foreach_path_from(stdin, nul_term_line) {\n\t/* now do something interesting with \"buf\"\n\t   and some other local variables */\n  }\n\nbut using function pointers for this kind of iteration is pretty awful\n(define the two-line loop body as a separate function, stuff any local\nvariables into a struct and pass it as \"void *\", etc). You can overcome\nthat with macros and make the above code work if you don't mind creating\nan undebuggable mess. :)\n\n builtin/check-attr.c     | 13 ++++++-------\n builtin/check-ignore.c   | 13 ++++++-------\n builtin/checkout-index.c | 11 ++++++-----\n builtin/hash-object.c    | 11 ++++++-----\n builtin/update-index.c   | 11 ++++++-----\n 5 files changed, 30 insertions(+), 29 deletions(-)\n\ndiff --git a/builtin/check-attr.c b/builtin/check-attr.c\nindex 087325e..53a5a18 100644\n--- a/builtin/check-attr.c\n+++ b/builtin/check-attr.c\n@@ -72,24 +72,23 @@ static void check_attr(const char *prefix, int cnt,\n static void check_attr_stdin_paths(const char *prefix, int cnt,\n \tstruct git_attr_check *check)\n {\n-\tstruct strbuf buf, nbuf;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct strbuf unquoted = STRBUF_INIT;\n \tstrbuf_getline_fn getline_fn;\n \n \tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n-\tstrbuf_init(&buf, 0);\n-\tstrbuf_init(&nbuf, 0);\n \twhile (getline_fn(&buf, stdin) != EOF) {\n \t\tif (!nul_term_line && buf.buf[0] == '\"') {\n-\t\t\tstrbuf_reset(&nbuf);\n-\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\tstrbuf_reset(&unquoted);\n+\t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t}\n \t\tcheck_attr(prefix, cnt, check, buf.buf);\n \t\tmaybe_flush_or_die(stdout, \"attribute to stdout\");\n \t}\n \tstrbuf_release(&buf);\n-\tstrbuf_release(&nbuf);\n+\tstrbuf_release(&unquoted);\n }\n \n static NORETURN void error_with_usage(const char *msg)\ndiff --git a/builtin/check-ignore.c b/builtin/check-ignore.c\nindex 4f0b09e..1d73d3c 100644\n--- a/builtin/check-ignore.c\n+++ b/builtin/check-ignore.c\n@@ -115,20 +115,19 @@ static int check_ignore(struct dir_struct *dir,\n \n static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n {\n-\tstruct strbuf buf, nbuf;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct strbuf unquoted = STRBUF_INIT;\n \tchar *pathspec[2] = { NULL, NULL };\n \tstrbuf_getline_fn getline_fn;\n \tint num_ignored = 0;\n \n \tgetline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;\n-\tstrbuf_init(&buf, 0);\n-\tstrbuf_init(&nbuf, 0);\n \twhile (getline_fn(&buf, stdin) != EOF) {\n \t\tif (!nul_term_line && buf.buf[0] == '\"') {\n-\t\t\tstrbuf_reset(&nbuf);\n-\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\tstrbuf_reset(&unquoted);\n+\t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t}\n \t\tpathspec[0] = buf.buf;\n \t\tnum_ignored += check_ignore(dir, prefix,\n@@ -136,7 +135,7 @@ static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)\n \t\tmaybe_flush_or_die(stdout, \"check-ignore to stdout\");\n \t}\n \tstrbuf_release(&buf);\n-\tstrbuf_release(&nbuf);\n+\tstrbuf_release(&unquoted);\n \treturn num_ignored;\n }\n \ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex ed888a5..d8d7bd3 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -251,7 +251,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (read_from_stdin) {\n-\t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\tstruct strbuf unquoted = STRBUF_INIT;\n \t\tstrbuf_getline_fn getline_fn;\n \n \t\tif (all)\n@@ -261,16 +262,16 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n-\t\t\t\tstrbuf_reset(&nbuf);\n-\t\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\t\tstrbuf_reset(&unquoted);\n+\t\t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n \t\t\t\t\tdie(\"line is badly quoted\");\n-\t\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t\t}\n \t\t\tp = prefix_path(prefix, prefix_length, buf.buf);\n \t\t\tcheckout_file(p, prefix);\n \t\t\tfree(p);\n \t\t}\n-\t\tstrbuf_release(&nbuf);\n+\t\tstrbuf_release(&unquoted);\n \t\tstrbuf_release(&buf);\n \t}\n \ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex ff20395..f7d3567 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -58,20 +58,21 @@ static void hash_object(const char *path, const char *type, const char *vpath,\n static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n \t\t\t     int literally)\n {\n-\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct strbuf unquoted = STRBUF_INIT;\n \n \twhile (strbuf_getline(&buf, stdin) != EOF) {\n \t\tif (buf.buf[0] == '\"') {\n-\t\t\tstrbuf_reset(&nbuf);\n-\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\tstrbuf_reset(&unquoted);\n+\t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n-\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t}\n \t\thash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,\n \t\t\t    literally);\n \t}\n \tstrbuf_release(&buf);\n-\tstrbuf_release(&nbuf);\n+\tstrbuf_release(&unquoted);\n }\n \n int cmd_hash_object(int argc, const char **argv, const char *prefix)\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 7c5c143..f052faf 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -1075,16 +1075,17 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (read_from_stdin) {\n-\t\tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\tstruct strbuf unquoted = STRBUF_INIT;\n \n \t\tsetup_work_tree();\n \t\twhile (getline_fn(&buf, stdin) != EOF) {\n \t\t\tchar *p;\n \t\t\tif (!nul_term_line && buf.buf[0] == '\"') {\n-\t\t\t\tstrbuf_reset(&nbuf);\n-\t\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\t\tstrbuf_reset(&unquoted);\n+\t\t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n \t\t\t\t\tdie(\"line is badly quoted\");\n-\t\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t\t}\n \t\t\tp = prefix_path(prefix, prefix_length, buf.buf);\n \t\t\tupdate_one(p);\n@@ -1092,7 +1093,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)\n \t\t\t\tchmod_path(set_executable_bit, p);\n \t\t\tfree(p);\n \t\t}\n-\t\tstrbuf_release(&nbuf);\n+\t\tstrbuf_release(&unquoted);\n \t\tstrbuf_release(&buf);\n \t}\n \n-- \n2.7.0.244.g0701a9d\n"},{"id":"276191","messageId":"20160115200856.GC11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-9-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 08/21] checkout-index: there are only two possible line terminations","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:08:56Z","receivedAt":"2016-01-15T20:08:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:23PM -0800, Junio C Hamano wrote:\n\n> @@ -144,10 +145,7 @@ static int option_parse_u(const struct option *opt,\n>  static int option_parse_z(const struct option *opt,\n>  \t\t\t  const char *arg, int unset)\n>  {\n> -\tif (unset)\n> -\t\tline_termination = '\\n';\n> -\telse\n> -\t\tline_termination = 0;\n> +\tnul_term_line = !unset;\n>  \treturn 0;\n>  }\n\nIs it worth doing this on top?\n\n-- >8 --\nSubject: [PATCH] checkout-index: simplify \"-z\" option parsing\n\nNow that we act as a simple bool, there's no need to use a\ncustom callback.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n builtin/checkout-index.c | 12 ++----------\n 1 file changed, 2 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\nindex d8d7bd3..3b913d1 100644\n--- a/builtin/checkout-index.c\n+++ b/builtin/checkout-index.c\n@@ -142,13 +142,6 @@ static int option_parse_u(const struct option *opt,\n \treturn 0;\n }\n \n-static int option_parse_z(const struct option *opt,\n-\t\t\t  const char *arg, int unset)\n-{\n-\tnul_term_line = !unset;\n-\treturn 0;\n-}\n-\n static int option_parse_prefix(const struct option *opt,\n \t\t\t       const char *arg, int unset)\n {\n@@ -192,9 +185,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n \t\t{ OPTION_CALLBACK, 'u', \"index\", &newfd, NULL,\n \t\t\tN_(\"update stat information in the index file\"),\n \t\t\tPARSE_OPT_NOARG, option_parse_u },\n-\t\t{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,\n-\t\t\tN_(\"paths are separated with NUL character\"),\n-\t\t\tPARSE_OPT_NOARG, option_parse_z },\n+\t\tOPT_BOOL('z', NULL, &nul_term_line,\n+\t\t\tN_(\"paths are separated with NUL character\")),\n \t\tOPT_BOOL(0, \"stdin\", &read_from_stdin,\n \t\t\tN_(\"read list of paths from the standard input\")),\n \t\tOPT_BOOL(0, \"temp\", &to_tempfile,\n-- \n2.7.0.244.g0701a9d\n"},{"id":"276195","messageId":"20160115202053.GA27640@sigill.intra.peff.net","threadId":"40059","inReplyTo":"20160115200856.GC11301@sigill.intra.peff.net","subject":"Re: [PATCH v4 08/21] checkout-index: there are only two possible line terminations","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:20:54Z","receivedAt":"2016-01-15T20:20:54Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 15, 2016 at 03:08:56PM -0500, Jeff King wrote:\n\n> Is it worth doing this on top?\n> \n> -- >8 --\n> Subject: [PATCH] checkout-index: simplify \"-z\" option parsing\n> \n> Now that we act as a simple bool, there's no need to use a\n> custom callback.\n\nOf course this is a backward step if we wanted to add negation. But I\nsuspect if we did so it would not be as \"--no-nul-termination\" (which\ninvolves inventing \"--nul-termination\" in the first place), but rather\nas a separate option. Anyway, since AFAIK nobody has plans to add one,\nthe code has been like this for years, we don't significantly impede\nanyone from doing it later, I'm inclined to err on the side of\nsimplifying.\n\nIf we do, there are two similar candidates:\n\n-- >8 --\nSubject: [PATCH] apply, ls-files: simplify \"-z\" parsing\n\nAs a short option, we cannot handle negation. Thus a\ncallback handling \"unset\" is overkill, and we can just use\nOPT_SET_INT instead to handle setting the option.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThese could also become OPT_BOOL, but then we have to translate that to\n'\\n' / NUL later in the code.\n\nI was also curious what \"--no-foo\" does (if a long option _is_ defined)\nwith OPT_SET_INT. It resets the value to 0, which would be wrong in this\ncase. I guess that makes a slight trap for anybody adding\n\"--nul-termination\" later (if they do not think about \n\"--no-nul-termination\", they may not realize it does not work). I'm not\nall that moved by that line of reasoning personally, though.\n\n builtin/apply.c    | 15 ++-------------\n builtin/ls-files.c | 13 ++-----------\n 2 files changed, 4 insertions(+), 24 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex deb1364..565f3fd 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -4464,16 +4464,6 @@ static int option_parse_p(const struct option *opt,\n \treturn 0;\n }\n \n-static int option_parse_z(const struct option *opt,\n-\t\t\t  const char *arg, int unset)\n-{\n-\tif (unset)\n-\t\tline_termination = '\\n';\n-\telse\n-\t\tline_termination = 0;\n-\treturn 0;\n-}\n-\n static int option_parse_space_change(const struct option *opt,\n \t\t\t  const char *arg, int unset)\n {\n@@ -4546,9 +4536,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)\n \t\t\t N_( \"attempt three-way merge if a patch does not apply\")),\n \t\tOPT_FILENAME(0, \"build-fake-ancestor\", &fake_ancestor,\n \t\t\tN_(\"build a temporary index based on embedded index information\")),\n-\t\t{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,\n-\t\t\tN_(\"paths are separated with NUL character\"),\n-\t\t\tPARSE_OPT_NOARG, option_parse_z },\n+\t\tOPT_SET_INT('z', NULL, &line_termination,\n+\t\t\tN_(\"paths are separated with NUL character\"), '\\0'),\n \t\tOPT_INTEGER('C', NULL, &p_context,\n \t\t\t\tN_(\"ensure at least <n> lines of context match\")),\n \t\t{ OPTION_CALLBACK, 0, \"whitespace\", &whitespace_option, N_(\"action\"),\ndiff --git a/builtin/ls-files.c b/builtin/ls-files.c\nindex b6a7cb0..59bad9b 100644\n--- a/builtin/ls-files.c\n+++ b/builtin/ls-files.c\n@@ -359,14 +359,6 @@ static const char * const ls_files_usage[] = {\n \tNULL\n };\n \n-static int option_parse_z(const struct option *opt,\n-\t\t\t  const char *arg, int unset)\n-{\n-\tline_terminator = unset ? '\\n' : '\\0';\n-\n-\treturn 0;\n-}\n-\n static int option_parse_exclude(const struct option *opt,\n \t\t\t\tconst char *arg, int unset)\n {\n@@ -408,9 +400,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)\n \tstruct exclude_list *el;\n \tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n \tstruct option builtin_ls_files_options[] = {\n-\t\t{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,\n-\t\t\tN_(\"paths are separated with NUL character\"),\n-\t\t\tPARSE_OPT_NOARG, option_parse_z },\n+\t\tOPT_SET_INT('z', NULL, &line_terminator,\n+\t\t\tN_(\"paths are separated with NUL character\"), '\\0'),\n \t\tOPT_BOOL('t', NULL, &show_tag,\n \t\t\tN_(\"identify the file status with tags\")),\n \t\tOPT_BOOL('v', NULL, &show_valid_bit,\n-- \n2.7.0.244.g0701a9d\n"},{"id":"276196","messageId":"20160115202318.GD11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-11-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 10/21] hash-object: read --stdin-paths with strbuf_getline()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:23:18Z","receivedAt":"2016-01-15T20:23:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:25PM -0800, Junio C Hamano wrote:\n\n> The list of paths could have been written with a DOS editor.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/hash-object.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n> \n> diff --git a/builtin/hash-object.c b/builtin/hash-object.c\n> index 3bc5ec1..ff20395 100644\n> --- a/builtin/hash-object.c\n> +++ b/builtin/hash-object.c\n> @@ -60,7 +60,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n>  {\n>  \tstruct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;\n>  \n> -\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n> +\twhile (strbuf_getline(&buf, stdin) != EOF) {\n>  \t\tif (buf.buf[0] == '\"') {\n>  \t\t\tstrbuf_reset(&nbuf);\n>  \t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n\nThe implication here is that the paths cannot have a trailing CR unless\nthey are quoted. I think that is probably OK. We quote such a case\nourselves, and while it's _possible_ for somebody to feed us arbitrary\noutput that they generated themselves, I would argue that anybody not\nquoting CR is generating bogus output.\n\n-Peff\n"},{"id":"276197","messageId":"20160115202729.GE11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-12-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 11/21] revision: read --stdin with strbuf_getline()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:27:29Z","receivedAt":"2016-01-15T20:27:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:26PM -0800, Junio C Hamano wrote:\n\n> Reading with getwholeline() and manually stripping the terminating\n> '\\n' would leave CR at the end of the line if the input comes from\n> a DOS editor.\n> \n> Constrasting this with the previous few changes, one may realize\n> that the way \"log\" family of commands read the paths with --stdin\n> looks inconsistent and sloppy.  It does not allow us to C-quote a\n> textual input, and it does not accept NUL-terminated records.  These\n> are unfortunately way too late to fix X-<.\n\nUnlike the previous patch, where we can reasonably expect somebody to\nquote a bare CR, this actually makes it impossible to ask about \"foo\\r\".\nWell, maybe not impossible, if we strip only one CR (you could say\n\"foo\\r\\r\"), but certainly a behavior change.\n\nGiven the general crappiness of this interface for files with bizarre\ncharacters, I think we are much more likely to be doing the user a favor\nby stripping CRLF than hurting them by breaking \"foo\\r\". After all,\n\"foo\\n\" remains impossible.\n\n-Peff\n"},{"id":"276199","messageId":"20160115203108.GF11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-17-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 16/21] transport-helper: read helper response with strbuf_getline()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:31:09Z","receivedAt":"2016-01-15T20:31:09Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:31PM -0800, Junio C Hamano wrote:\n\n> Our implementation of helpers never use CRLF line endings, and they\n> do not depend on the ability to place a CR as payload at the end of\n> the line, so this is essentially a no-op for in-tree users.  However,\n> this allows third-party implementation of helpers to give us their\n> line with CRLF line ending (they cannot expect us to feed CRLF to\n> them, though).\n\nI think this is OK. I cannot think of any transport-helper request or\nresponse which wants to pass anything more exotic than a refname as its\nfinal argument. And if we were to add one, it would need to take care to\nquote its argument somehow to allow \"\\n\" anyway.\n\n-Peff\n"},{"id":"276201","messageId":"20160115204118.GG11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-18-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 17/21] cat-file: read batch stream with strbuf_getline()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:41:19Z","receivedAt":"2016-01-15T20:41:19Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:32PM -0800, Junio C Hamano wrote:\n\n> It is possible to prepare a text file with a DOS editor and feed it\n> as a batch command stream to the command.\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n> ---\n>  builtin/cat-file.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n> \n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index d2ebaf1..54db118 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -401,7 +401,7 @@ static int batch_objects(struct batch_options *opt)\n>  \tsave_warning = warn_on_object_refname_ambiguity;\n>  \twarn_on_object_refname_ambiguity = 0;\n>  \n> -\twhile (strbuf_getline_lf(&buf, stdin) != EOF) {\n> +\twhile (strbuf_getline(&buf, stdin) != EOF) {\n\nThis function can actually take a pretty wide variety of input. It can\ntake anything that get_sha1() will handle. So I think that:\n\n  printf ':/foo\\r\\n' | git cat-file --batch\n\nwill behave differently (before, we looked for the literal \"foo\\r\" in a\ncommit message). That's sufficiently crazy that I'm OK with giving it\nup.\n\nA more interesting case is \"rev-list\" output, combined with \"%(rest)\".\nThe former does not quote its filenames.\n\nSo in a repo like this:\n\n  echo bar >$(printf 'foo\\r')\n  git add .\n  git commit -m one\n\nyou can currently do:\n\n  git rev-list --objects --all |\n  git cat-file --batch-check='%(objectsize) %(rest)' |\n  cat -A\n\nand get:\n\n  154 $\n  32 $\n  4 foo^M$\n\nbut with your patch, we lose the CR, and get a filename that is not\nactually contained in the repo.\n\nI think I'm still in favor of the change, though, for the same reason as\nsome of the earlier ones. We already can't handle \"foo\\n\", so this\ncannot be considered a completely robust interface. And we are much more\nlikely to do good than harm by stripping such a CR.\n\n-Peff\n"},{"id":"276202","messageId":"20160115204325.GH11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-19-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 18/21] column: read lines with strbuf_getline()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:43:25Z","receivedAt":"2016-01-15T20:43:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:33PM -0800, Junio C Hamano wrote:\n\n> Multiple lines read here are concatenated on a single line to form a\n> multi-column output line.  We do not want to have a CR at the end,\n> even if the input file consists of CRLF terminated lines.\n\nHrm. I suspect this is OK in practice, though \"git column\" can\ntechnically receive unbounded input from the user. We don't specify in\nthe documentation that it must be text, but I guess it's somewhat\nimplied by the use of the word \"line\".\n\n-Peff\n"},{"id":"276203","messageId":"20160115204916.GJ11301@sigill.intra.peff.net","threadId":"40059","inReplyTo":"1452815916-6447-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v4 00/21] Peace with CRLF","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T20:49:16Z","receivedAt":"2016-01-15T20:49:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 14, 2016 at 03:58:15PM -0800, Junio C Hamano wrote:\n\n> This is a reroll of\n> \n>   http://thread.gmane.org/gmane.comp.version-control.git/282614\n> \n> which is a continuation to $gmane/275735, which is filed in the\n> archive under another mailing list:\n> \n>   http://thread.gmane.org/gmane.comp.version-control.msysgit/21773\n\nI just read through the whole thing and made a few comments. Please feel\nfree to ignore my \"how about this on top\" suggestions if you don't like\nthem, or just don't want to deal with them. Patches I didn't respond to\nall looked good to me.\n\nThere are a few \"iffy\" conversions where we take unconstrained input and\nthere's no \"usual\" quoting mechanism available (you mentioned the one in\n\"grep\", and I pointed out a few more). I hate to break\nbackwards-compatibility in any way, but I think in all of those cases\nthat we are much more likely to be helping the user than hurting them.\n\nSo I think it's a net benefit in all of the cases.\n\n-Peff\n"},{"id":"276204","messageId":"xmqq60yuh74w.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"20160115193640.GA19291@sigill.intra.peff.net","subject":"Re: [PATCH v4 05/21] check-attr: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-15T21:20:31Z","receivedAt":"2016-01-15T21:20:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Apparently we use this pattern in quite a few places (or they all copied\n> from each other). Here's a possible fixup that could go after your\n> series (it could go before, too, but it creates a lot of textual\n> conflicts with your stuff).\n\nSounds good, but I'm in favor of leaving this as an unrelated\nclean-up that happens to touch the same area.\n"},{"id":"276205","messageId":"xmqq1t9ih72f.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"20160115200856.GC11301@sigill.intra.peff.net","subject":"Re: [PATCH v4 08/21] checkout-index: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-15T21:22:00Z","receivedAt":"2016-01-15T21:22:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Jan 14, 2016 at 03:58:23PM -0800, Junio C Hamano wrote:\n>\n>> @@ -144,10 +145,7 @@ static int option_parse_u(const struct option *opt,\n>>  static int option_parse_z(const struct option *opt,\n>>  \t\t\t  const char *arg, int unset)\n>>  {\n>> -\tif (unset)\n>> -\t\tline_termination = '\\n';\n>> -\telse\n>> -\t\tline_termination = 0;\n>> +\tnul_term_line = !unset;\n>>  \treturn 0;\n>>  }\n>\n> Is it worth doing this on top?\n\nYes.\n\nTo be bluntly honest, the above callback has no right to exist.  I\nshould have turned it from OPTION_CALLBACK to OPT_BOOL from the\nstart.\n\n>\n> -- >8 --\n> Subject: [PATCH] checkout-index: simplify \"-z\" option parsing\n>\n> Now that we act as a simple bool, there's no need to use a\n> custom callback.\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n\n\n\n>  builtin/checkout-index.c | 12 ++----------\n>  1 file changed, 2 insertions(+), 10 deletions(-)\n>\n> diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c\n> index d8d7bd3..3b913d1 100644\n> --- a/builtin/checkout-index.c\n> +++ b/builtin/checkout-index.c\n> @@ -142,13 +142,6 @@ static int option_parse_u(const struct option *opt,\n>  \treturn 0;\n>  }\n>  \n> -static int option_parse_z(const struct option *opt,\n> -\t\t\t  const char *arg, int unset)\n> -{\n> -\tnul_term_line = !unset;\n> -\treturn 0;\n> -}\n> -\n>  static int option_parse_prefix(const struct option *opt,\n>  \t\t\t       const char *arg, int unset)\n>  {\n> @@ -192,9 +185,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix)\n>  \t\t{ OPTION_CALLBACK, 'u', \"index\", &newfd, NULL,\n>  \t\t\tN_(\"update stat information in the index file\"),\n>  \t\t\tPARSE_OPT_NOARG, option_parse_u },\n> -\t\t{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,\n> -\t\t\tN_(\"paths are separated with NUL character\"),\n> -\t\t\tPARSE_OPT_NOARG, option_parse_z },\n> +\t\tOPT_BOOL('z', NULL, &nul_term_line,\n> +\t\t\tN_(\"paths are separated with NUL character\")),\n>  \t\tOPT_BOOL(0, \"stdin\", &read_from_stdin,\n>  \t\t\tN_(\"read list of paths from the standard input\")),\n>  \t\tOPT_BOOL(0, \"temp\", &to_tempfile,\n"},{"id":"276206","messageId":"20160115212300.GB29698@sigill.intra.peff.net","threadId":"40059","inReplyTo":"xmqq60yuh74w.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 05/21] check-attr: there are only two possible line terminations","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-01-15T21:23:00Z","receivedAt":"2016-01-15T21:23:00Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jan 15, 2016 at 01:20:31PM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > Apparently we use this pattern in quite a few places (or they all copied\n> > from each other). Here's a possible fixup that could go after your\n> > series (it could go before, too, but it creates a lot of textual\n> > conflicts with your stuff).\n> \n> Sounds good, but I'm in favor of leaving this as an unrelated\n> clean-up that happens to touch the same area.\n\nWould you prefer me to hold it and send it later, after your series is\nmerged, or just rebase it on master, have it graduate separately, and\nlet you deal with the conflicts?\n\n-Peff\n"},{"id":"276207","messageId":"xmqqwprafs4u.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"20160115212300.GB29698@sigill.intra.peff.net","subject":"Re: [PATCH v4 05/21] check-attr: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-15T21:29:53Z","receivedAt":"2016-01-15T21:29:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>> Sounds good, but I'm in favor of leaving this as an unrelated\n>> clean-up that happens to touch the same area.\n>\n> Would you prefer me to hold it and send it later, after your series is\n> merged, or just rebase it on master, have it graduate separately, and\n> let you deal with the conflicts?\n\nIf you give me a choice, then I'd take the one that leaves less for\nme to keep track of ;-)\n\nThanks.\n"},{"id":"276219","messageId":"xmqq8u3qfmix.fsf@gitster.mtv.corp.google.com","threadId":"40059","inReplyTo":"xmqq1t9ih72f.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v4 08/21] checkout-index: there are only two possible line terminations","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-15T23:31:02Z","receivedAt":"2016-01-15T23:31:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jeff King <peff@peff.net> writes:\n>\n>> On Thu, Jan 14, 2016 at 03:58:23PM -0800, Junio C Hamano wrote:\n>>\n>>> @@ -144,10 +145,7 @@ static int option_parse_u(const struct option *opt,\n>>>  static int option_parse_z(const struct option *opt,\n>>>  \t\t\t  const char *arg, int unset)\n>>>  {\n>>> -\tif (unset)\n>>> -\t\tline_termination = '\\n';\n>>> -\telse\n>>> -\t\tline_termination = 0;\n>>> +\tnul_term_line = !unset;\n>>>  \treturn 0;\n>>>  }\n>>\n>> Is it worth doing this on top?\n>\n> Yes.\n>\n> To be bluntly honest, the above callback has no right to exist.  I\n> should have turned it from OPTION_CALLBACK to OPT_BOOL from the\n> start.\n\nHaving said that, I'd leave this change out of my tree for now,\nuntil the patches 1-9, which I'll split out from the rest of the\nseries into a separate topic, moves out of the way.\n\nI have this suspicion that \"checkout-index\" inherited the peculiar\nstance \"update-index\" took about the command line arguments and\noptions (e.g. \"update-index A --add B\" and \"update-index --add A B\"\ndo different things for path \"A\").\n\nAs far as I can see, there is no reason why \"-u\", just like \"-z\"\nthat you noticed, has to be processed immediately as it is read\nbefore processing the remainder of the command line.  And I think\nthe change you suggested to stop using a callback for \"-z\" is better\ndone with the same patch as the one that fixes \"-u\", whose log\nmessage would probably be:\n\n    checkout-index: simplify option parsing\n\n    For some reason, the command line parser for \"-u\" and \"-z\"\n    options tried to make the effect of the options as they are\n    processed by using OPTION_CALLBACK, but there is no reason\n    to do so.  Just flip the bit to remember that we have seen\n    these options while parsing the command line, and use them\n    after we are done parsing, just like all other options.\n\nor something.\n"}]}