Skip to content

Commit

Permalink
Always accept newline as a name terminator
Browse files Browse the repository at this point in the history
This avoids including the newline character as part of the name when it
is the last name on a line. Also split out functions for quoted and
unquoted names to clarify the logic.
  • Loading branch information
bluekeyes committed Mar 21, 2019
1 parent 631c705 commit c818281
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 27 deletions.
66 changes: 39 additions & 27 deletions gitdiff/file_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,41 +199,53 @@ func parseMode(s string) (os.FileMode, error) {
// slashes are collapsed.
func parseName(s string, term rune, dropPrefix int) (name string, n int, err error) {
if len(s) > 0 && s[0] == '"' {
// find matching end quote and then unquote the section
for n = 1; n < len(s); n++ {
if s[n] == '"' && s[n-1] != '\\' {
n++
break
}
}
if n == 2 {
return "", 0, fmt.Errorf("missing name")
}
if name, err = strconv.Unquote(s[:n]); err != nil {
return "", 0, err
}
name, n, err = parseQuotedName(s)
} else {
// find terminator and take the previous section
for n = 0; n < len(s); n++ {
if term >= 0 && rune(s[n]) == term {
break
}
if term < 0 && (s[n] == ' ' || s[n] == '\t') {
break
}
}
if n == 0 {
return "", 0, fmt.Errorf("missing name")
}
name = s[:n]
name, n, err = parseUnquotedName(s, term)
}
if err != nil {
return "", 0, err
}

if name == devNull {
return name, n, nil
}
return cleanName(name, dropPrefix), n, nil
}

func parseQuotedName(s string) (name string, n int, err error) {
for n = 1; n < len(s); n++ {
if s[n] == '"' && s[n-1] != '\\' {
n++
break
}
}
if n == 2 {
return "", 0, fmt.Errorf("missing name")
}
if name, err = strconv.Unquote(s[:n]); err != nil {
return "", 0, err
}
return name, n, err
}

func parseUnquotedName(s string, term rune) (name string, n int, err error) {
for n = 0; n < len(s); n++ {
if s[n] == '\n' {
break
}
if term >= 0 && rune(s[n]) == term {
break
}
if term < 0 && (s[n] == ' ' || s[n] == '\t') {
break
}
}
if n == 0 {
return "", 0, fmt.Errorf("missing name")
}
return s[:n], n, nil
}

// verifyGitHeaderName checks a parsed name against state set by previous lines
func verifyGitHeaderName(parsed, existing string, isNull bool, side string) error {
if existing != "" {
Expand Down
3 changes: 3 additions & 0 deletions gitdiff/file_header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ func TestParseName(t *testing.T) {
"devNull": {
Input: "/dev/null", Term: '\t', Drop: 1, Output: "/dev/null", N: 9,
},
"newlineAlwaysSeparates": {
Input: "dir/file.txt\n", Term: 0, Output: "dir/file.txt", N: 12,
},
"emptyString": {
Input: "", Err: true,
},
Expand Down

0 comments on commit c818281

Please sign in to comment.