@@ -32,8 +32,9 @@ static int apply = 1;
3232static int no_add = 0 ;
3333static int show_index_info = 0 ;
3434static int line_termination = '\n' ;
35+ static unsigned long p_context = -1 ;
3536static const char apply_usage [] =
36- "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>..." ;
37+ "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [- -whitespace=<nowarn|warn|error|error-all|strip>] <patch>..." ;
3738
3839static enum whitespace_eol {
3940 nowarn_whitespace ,
@@ -100,6 +101,7 @@ static int max_change, max_len;
100101static int linenr = 1 ;
101102
102103struct fragment {
104+ unsigned long leading , trailing ;
103105 unsigned long oldpos , oldlines ;
104106 unsigned long newpos , newlines ;
105107 const char * patch ;
@@ -817,12 +819,15 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
817819 int added , deleted ;
818820 int len = linelen (line , size ), offset ;
819821 unsigned long oldlines , newlines ;
822+ unsigned long leading , trailing ;
820823
821824 offset = parse_fragment_header (line , len , fragment );
822825 if (offset < 0 )
823826 return -1 ;
824827 oldlines = fragment -> oldlines ;
825828 newlines = fragment -> newlines ;
829+ leading = 0 ;
830+ trailing = 0 ;
826831
827832 if (patch -> is_new < 0 ) {
828833 patch -> is_new = !oldlines ;
@@ -860,10 +865,14 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
860865 case ' ' :
861866 oldlines -- ;
862867 newlines -- ;
868+ if (!deleted && !added )
869+ leading ++ ;
870+ trailing ++ ;
863871 break ;
864872 case '-' :
865873 deleted ++ ;
866874 oldlines -- ;
875+ trailing = 0 ;
867876 break ;
868877 case '+' :
869878 /*
@@ -887,6 +896,7 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
887896 }
888897 added ++ ;
889898 newlines -- ;
899+ trailing = 0 ;
890900 break ;
891901
892902 /* We allow "\ No newline at end of file". Depending
@@ -904,6 +914,9 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
904914 }
905915 if (oldlines || newlines )
906916 return -1 ;
917+ fragment -> leading = leading ;
918+ fragment -> trailing = trailing ;
919+
907920 /* If a fragment ends with an incomplete line, we failed to include
908921 * it in the above loop because we hit oldlines == newlines == 0
909922 * before seeing it.
@@ -1087,7 +1100,7 @@ static int read_old_data(struct stat *st, const char *path, void *buf, unsigned
10871100 }
10881101}
10891102
1090- static int find_offset (const char * buf , unsigned long size , const char * fragment , unsigned long fragsize , int line )
1103+ static int find_offset (const char * buf , unsigned long size , const char * fragment , unsigned long fragsize , int line , int * lines )
10911104{
10921105 int i ;
10931106 unsigned long start , backwards , forwards ;
@@ -1148,6 +1161,7 @@ static int find_offset(const char *buf, unsigned long size, const char *fragment
11481161 n = (i >> 1 )+ 1 ;
11491162 if (i & 1 )
11501163 n = - n ;
1164+ * lines = n ;
11511165 return try ;
11521166 }
11531167
@@ -1157,6 +1171,33 @@ static int find_offset(const char *buf, unsigned long size, const char *fragment
11571171 return -1 ;
11581172}
11591173
1174+ static void remove_first_line (const char * * rbuf , int * rsize )
1175+ {
1176+ const char * buf = * rbuf ;
1177+ int size = * rsize ;
1178+ unsigned long offset ;
1179+ offset = 0 ;
1180+ while (offset <= size ) {
1181+ if (buf [offset ++ ] == '\n' )
1182+ break ;
1183+ }
1184+ * rsize = size - offset ;
1185+ * rbuf = buf + offset ;
1186+ }
1187+
1188+ static void remove_last_line (const char * * rbuf , int * rsize )
1189+ {
1190+ const char * buf = * rbuf ;
1191+ int size = * rsize ;
1192+ unsigned long offset ;
1193+ offset = size - 1 ;
1194+ while (offset > 0 ) {
1195+ if (buf [-- offset ] == '\n' )
1196+ break ;
1197+ }
1198+ * rsize = offset + 1 ;
1199+ }
1200+
11601201struct buffer_desc {
11611202 char * buffer ;
11621203 unsigned long size ;
@@ -1192,7 +1233,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
11921233 int offset , size = frag -> size ;
11931234 char * old = xmalloc (size );
11941235 char * new = xmalloc (size );
1236+ const char * oldlines , * newlines ;
11951237 int oldsize = 0 , newsize = 0 ;
1238+ unsigned long leading , trailing ;
1239+ int pos , lines ;
11961240
11971241 while (size > 0 ) {
11981242 int len = linelen (patch , size );
@@ -1241,23 +1285,59 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
12411285 newsize -- ;
12421286 }
12431287#endif
1244-
1245- offset = find_offset (buf , desc -> size , old , oldsize , frag -> newpos );
1246- if (offset >= 0 ) {
1247- int diff = newsize - oldsize ;
1248- unsigned long size = desc -> size + diff ;
1249- unsigned long alloc = desc -> alloc ;
1250-
1251- if (size > alloc ) {
1252- alloc = size + 8192 ;
1253- desc -> alloc = alloc ;
1254- buf = xrealloc (buf , alloc );
1255- desc -> buffer = buf ;
1288+
1289+ oldlines = old ;
1290+ newlines = new ;
1291+ leading = frag -> leading ;
1292+ trailing = frag -> trailing ;
1293+ lines = 0 ;
1294+ pos = frag -> newpos ;
1295+ for (;;) {
1296+ offset = find_offset (buf , desc -> size , oldlines , oldsize , pos , & lines );
1297+ if (offset >= 0 ) {
1298+ int diff = newsize - oldsize ;
1299+ unsigned long size = desc -> size + diff ;
1300+ unsigned long alloc = desc -> alloc ;
1301+
1302+ /* Warn if it was necessary to reduce the number
1303+ * of context lines.
1304+ */
1305+ if ((leading != frag -> leading ) || (trailing != frag -> trailing ))
1306+ fprintf (stderr , "Context reduced to (%ld/%ld) to apply fragment at %d\n" ,
1307+ leading , trailing , pos + lines );
1308+
1309+ if (size > alloc ) {
1310+ alloc = size + 8192 ;
1311+ desc -> alloc = alloc ;
1312+ buf = xrealloc (buf , alloc );
1313+ desc -> buffer = buf ;
1314+ }
1315+ desc -> size = size ;
1316+ memmove (buf + offset + newsize , buf + offset + oldsize , size - offset - newsize );
1317+ memcpy (buf + offset , newlines , newsize );
1318+ offset = 0 ;
1319+
1320+ break ;
1321+ }
1322+
1323+ /* Am I at my context limits? */
1324+ if ((leading <= p_context ) && (trailing <= p_context ))
1325+ break ;
1326+ /* Reduce the number of context lines
1327+ * Reduce both leading and trailing if they are equal
1328+ * otherwise just reduce the larger context.
1329+ */
1330+ if (leading >= trailing ) {
1331+ remove_first_line (& oldlines , & oldsize );
1332+ remove_first_line (& newlines , & newsize );
1333+ pos -- ;
1334+ leading -- ;
1335+ }
1336+ if (trailing > leading ) {
1337+ remove_last_line (& oldlines , & oldsize );
1338+ remove_last_line (& newlines , & newsize );
1339+ trailing -- ;
12561340 }
1257- desc -> size = size ;
1258- memmove (buf + offset + newsize , buf + offset + oldsize , size - offset - newsize );
1259- memcpy (buf + offset , new , newsize );
1260- offset = 0 ;
12611341 }
12621342
12631343 free (old );
@@ -1882,6 +1962,7 @@ int main(int argc, char **argv)
18821962
18831963 for (i = 1 ; i < argc ; i ++ ) {
18841964 const char * arg = argv [i ];
1965+ char * end ;
18851966 int fd ;
18861967
18871968 if (!strcmp (arg , "-" )) {
@@ -1945,6 +2026,12 @@ int main(int argc, char **argv)
19452026 line_termination = 0 ;
19462027 continue ;
19472028 }
2029+ if (!strncmp (arg , "-C" , 2 )) {
2030+ p_context = strtoul (arg + 2 , & end , 0 );
2031+ if (* end != '\0' )
2032+ die ("unrecognized context count '%s'" , arg + 2 );
2033+ continue ;
2034+ }
19482035 if (!strncmp (arg , "--whitespace=" , 13 )) {
19492036 whitespace_option = arg + 13 ;
19502037 parse_whitespace_option (arg + 13 );
0 commit comments