1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package email 5 6 import ( 7 "bufio" 8 "fmt" 9 "strings" 10 ) 11 12 func ParsePatch(text string) (title string, diff string, err error) { 13 s := bufio.NewScanner(strings.NewReader(text)) 14 parsingDiff := false 15 diffStarted := false 16 lastLine := "" 17 for s.Scan() { 18 ln := s.Text() 19 if strings.HasPrefix(ln, "--- a/") || strings.HasPrefix(ln, "--- /dev/null") { 20 parsingDiff = true 21 if title == "" { 22 title = lastLine 23 } 24 } 25 if parsingDiff { 26 if ln == "" || ln == "--" || ln == "-- " || ln[0] == '>' || 27 ln[0] >= 'A' && ln[0] <= 'Z' { 28 break 29 } 30 diff += ln + "\n" 31 continue 32 } 33 if strings.HasPrefix(ln, "diff --git") { 34 diffStarted = true 35 continue 36 } 37 if strings.HasPrefix(ln, "Subject: ") { 38 title = ln[len("Subject: "):] 39 continue 40 } 41 if ln == "" || title != "" || diffStarted { 42 continue 43 } 44 lastLine = ln 45 if strings.HasPrefix(ln, " ") { 46 title = ln[4:] 47 } 48 } 49 if err = s.Err(); err != nil { 50 return 51 } 52 if strings.Contains(strings.ToLower(title), "[patch") { 53 pos := strings.IndexByte(title, ']') 54 if pos == -1 { 55 err = fmt.Errorf("title contains '[patch' but not ']'") 56 return 57 } 58 title = title[pos+1:] 59 } 60 title = strings.TrimSpace(title) 61 if title == "" { 62 err = fmt.Errorf("failed to extract title") 63 return 64 } 65 if diff == "" { 66 err = fmt.Errorf("failed to extract diff") 67 return 68 } 69 return 70 } 71