@@ -28,49 +28,118 @@ static int remove_space(char *line)
2828 return dst - line ;
2929}
3030
31- static void generate_id_list (void )
31+ static int scan_hunk_header (const char * p , int * p_before , int * p_after )
32+ {
33+ static const char digits [] = "0123456789" ;
34+ const char * q , * r ;
35+ int n ;
36+
37+ q = p + 4 ;
38+ n = strspn (q , digits );
39+ if (q [n ] == ',' ) {
40+ q += n + 1 ;
41+ n = strspn (q , digits );
42+ }
43+ if (n == 0 || q [n ] != ' ' || q [n + 1 ] != '+' )
44+ return 0 ;
45+
46+ r = q + n + 2 ;
47+ n = strspn (r , digits );
48+ if (r [n ] == ',' ) {
49+ r += n + 1 ;
50+ n = strspn (r , digits );
51+ }
52+ if (n == 0 )
53+ return 0 ;
54+
55+ * p_before = atoi (q );
56+ * p_after = atoi (r );
57+ return 1 ;
58+ }
59+
60+ int get_one_patchid (unsigned char * next_sha1 , git_SHA_CTX * ctx )
3261{
33- static unsigned char sha1 [20 ];
3462 static char line [1000 ];
35- git_SHA_CTX ctx ;
36- int patchlen = 0 ;
63+ int patchlen = 0 , found_next = 0 ;
64+ int before = -1 , after = -1 ;
3765
38- git_SHA1_Init (& ctx );
3966 while (fgets (line , sizeof (line ), stdin ) != NULL ) {
40- unsigned char n [20 ];
4167 char * p = line ;
4268 int len ;
4369
4470 if (!memcmp (line , "diff-tree " , 10 ))
4571 p += 10 ;
4672 else if (!memcmp (line , "commit " , 7 ))
4773 p += 7 ;
74+ else if (!memcmp (line , "From " , 5 ))
75+ p += 5 ;
4876
49- if (!get_sha1_hex (p , n )) {
50- flush_current_id (patchlen , sha1 , & ctx );
51- hashcpy (sha1 , n );
52- patchlen = 0 ;
53- continue ;
77+ if (!get_sha1_hex (p , next_sha1 )) {
78+ found_next = 1 ;
79+ break ;
5480 }
5581
5682 /* Ignore commit comments */
5783 if (!patchlen && memcmp (line , "diff " , 5 ))
5884 continue ;
5985
60- /* Ignore git-diff index header */
61- if (!memcmp (line , "index " , 6 ))
62- continue ;
86+ /* Parsing diff header? */
87+ if (before == -1 ) {
88+ if (!memcmp (line , "index " , 6 ))
89+ continue ;
90+ else if (!memcmp (line , "--- " , 4 ))
91+ before = after = 1 ;
92+ else if (!isalpha (line [0 ]))
93+ break ;
94+ }
6395
64- /* Ignore line numbers when computing the SHA1 of the patch */
65- if (!memcmp (line , "@@ -" , 4 ))
66- continue ;
96+ /* Looking for a valid hunk header? */
97+ if (before == 0 && after == 0 ) {
98+ if (!memcmp (line , "@@ -" , 4 )) {
99+ /* Parse next hunk, but ignore line numbers. */
100+ scan_hunk_header (line , & before , & after );
101+ continue ;
102+ }
103+
104+ /* Split at the end of the patch. */
105+ if (memcmp (line , "diff " , 5 ))
106+ break ;
107+
108+ /* Else we're parsing another header. */
109+ before = after = -1 ;
110+ }
111+
112+ /* If we get here, we're inside a hunk. */
113+ if (line [0 ] == '-' || line [0 ] == ' ' )
114+ before -- ;
115+ if (line [0 ] == '+' || line [0 ] == ' ' )
116+ after -- ;
67117
68118 /* Compute the sha without whitespace */
69119 len = remove_space (line );
70120 patchlen += len ;
71- git_SHA1_Update (& ctx , line , len );
121+ git_SHA1_Update (ctx , line , len );
122+ }
123+
124+ if (!found_next )
125+ hashclr (next_sha1 );
126+
127+ return patchlen ;
128+ }
129+
130+ static void generate_id_list (void )
131+ {
132+ unsigned char sha1 [20 ], n [20 ];
133+ git_SHA_CTX ctx ;
134+ int patchlen ;
135+
136+ git_SHA1_Init (& ctx );
137+ hashclr (sha1 );
138+ while (!feof (stdin )) {
139+ patchlen = get_one_patchid (n , & ctx );
140+ flush_current_id (patchlen , sha1 , & ctx );
141+ hashcpy (sha1 , n );
72142 }
73- flush_current_id (patchlen , sha1 , & ctx );
74143}
75144
76145static const char patch_id_usage [] = "git patch-id < patch" ;
0 commit comments