patch: support for patches without dates and generated with -U1; shrink
No binary (build failed)
—
(log yok)
| @@ -44,23 +44,23 @@ static unsigned copy_lines(FILE *src_stream, FILE *dest_stream, unsigned lines_c | |
| * returns malloc'ed filename | |
| * NB: frees 1st argument! | |
| */ | |
| - | static char *extract_filename_and_free_line(char *line, int patch_level) |
| + | static char *extract_filename(char *line, int patch_level, const char *pat) |
| { | |
| - | char *temp, *filename_start_ptr = line + 4; |
| + | char *temp = NULL, *filename_start_ptr = line + 4; |
| - | /* Terminate string at end of source filename */ |
| - | temp = strchrnul(filename_start_ptr, '\t'); |
| - | *temp = '\0'; |
| + | if (strncmp(line, pat, 4) == 0) { |
| + | /* Terminate string at end of source filename */ |
| + | line[strcspn(line,"\t\n\r")] = '\0'; |
| - | /* Skip over (patch_level) number of leading directories */ |
| - | while (patch_level--) { |
| - | temp = strchr(filename_start_ptr, '/'); |
| - | if (!temp) |
| - | break; |
| - | filename_start_ptr = temp + 1; |
| + | /* Skip over (patch_level) number of leading directories */ |
| + | while (patch_level--) { |
| + | temp = strchr(filename_start_ptr, '/'); |
| + | if (!temp) |
| + | break; |
| + | filename_start_ptr = temp + 1; |
| + | } |
| + | temp = xstrdup(filename_start_ptr); |
| } | |
| - | |
| - | temp = xstrdup(filename_start_ptr); |
| free(line); | |
| return temp; | |
| } | |
| @@ -100,30 +100,26 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| /* Skip everything upto the "---" marker | |
| * No need to parse the lines "Only in <dir>", and "diff <args>" | |
| */ | |
| - | while (strncmp(patch_line, "--- ", 4) != 0) { |
| - | free(patch_line); |
| + | do { |
| + | /* Extract the filename used before the patch was generated */ |
| + | original_filename = extract_filename(patch_line, patch_level, "--- "); |
| patch_line = xmalloc_getline(patch_file); | |
| - | if (!patch_line) |
| - | bb_error_msg_and_die("invalid patch"); |
| - | } |
| - | |
| - | /* Extract the filename used before the patch was generated */ |
| - | original_filename = extract_filename_and_free_line(patch_line, patch_level); |
| + | if (!patch_line) goto quit; |
| + | } while (!original_filename); |
| - | patch_line = xmalloc_getline(patch_file); |
| - | if (!patch_line || strncmp(patch_line, "+++ ", 4) != 0) |
| + | new_filename = extract_filename(patch_line, patch_level, "+++ "); |
| + | if (!new_filename) { |
| bb_error_msg_and_die("invalid patch"); | |
| - | new_filename = extract_filename_and_free_line(patch_line, patch_level); |
| + | } |
| - | /* Get access rights from the file to be patched, -1 file does not exist */ |
| + | /* Get access rights from the file to be patched */ |
| if (stat(new_filename, &saved_stat) != 0) { | |
| - | char *line_ptr; |
| - | /* Create leading directories */ |
| - | line_ptr = strrchr(new_filename, '/'); |
| - | if (line_ptr) { |
| - | *line_ptr = '\0'; |
| + | char *slash = strrchr(new_filename, '/'); |
| + | if (slash) { |
| + | /* Create leading directories */ |
| + | *slash = '\0'; |
| bb_make_directory(new_filename, -1, FILEUTILS_RECUR); | |
| - | *line_ptr = '/'; |
| + | *slash = '/'; |
| } | |
| backup_filename = NULL; | |
| saved_stat.st_mode = 0644; | |
| @@ -134,10 +130,16 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| dst_stream = xfopen(new_filename, "w"); | |
| fchmod(fileno(dst_stream), saved_stat.st_mode); | |
| src_stream = NULL; | |
| - | |
| - | if (backup_filename && !stat(original_filename, &saved_stat)) { |
| - | src_stream = xfopen((strcmp(original_filename, new_filename)) ? |
| - | original_filename : backup_filename, "r"); |
| + | if (backup_filename && stat(original_filename, &saved_stat) == 0) { |
| + | // strcmp() is never 0! Otherwise: |
| + | // original_filename == new_filename, |
| + | // stat(original_filename) == stat(new_filename), |
| + | // stat(new_filename) == 0, |
| + | // but we renamed new_filename if it existed! |
| + | // stat() must fail! |
| + | //src_stream = xfopen((strcmp(original_filename, new_filename)) ? |
| + | // original_filename : backup_filename, "r"); |
| + | src_stream = xfopen(original_filename, "r"); |
| } | |
| printf("patching file %s\n", new_filename); | |
| @@ -147,16 +149,12 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| while (patch_line) { | |
| unsigned count; | |
| unsigned src_beg_line; | |
| - | unsigned unused; |
| - | unsigned hunk_offset_start = 0; |
| - | smallint hunk_error = 0; |
| - | |
| - | /* This bit should be improved */ |
| - | if ((sscanf(patch_line, "@@ -%d,%d +%d,%d @@", &src_beg_line, &unused, &dest_beg_line, &unused) != 4) |
| - | && (sscanf(patch_line, "@@ -%d,%d +%d @@", &src_beg_line, &unused, &dest_beg_line) != 3) |
| - | && (sscanf(patch_line, "@@ -%d +%d,%d @@", &src_beg_line, &dest_beg_line, &unused) != 3) |
| - | ) { |
| - | /* No more hunks for this file */ |
| + | unsigned hunk_offset_start; |
| + | unsigned src_last_line = 1; |
| + | |
| + | if ((sscanf(patch_line, "@@ -%d,%d +%d", &src_beg_line, &src_last_line, &dest_beg_line) != 3) |
| + | && (sscanf(patch_line, "@@ -%d +%d", &src_beg_line, &dest_beg_line) != 2) |
| + | ) { /* No more hunks for this file */ |
| break; | |
| } | |
| hunk_count++; | |
| @@ -172,14 +170,22 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| dest_cur_line += count; | |
| copy_trailing_lines_flag = 1; | |
| } | |
| - | hunk_offset_start = src_cur_line; |
| + | src_last_line += hunk_offset_start = src_cur_line; |
| while (1) { | |
| free(patch_line); | |
| patch_line = xmalloc_fgets(patch_file); | |
| - | if (patch_line == NULL) break; |
| - | if ((*patch_line == '-') || (*patch_line == ' ')) { |
| + | if (patch_line == NULL) |
| + | break; /* EOF */ |
| + | if ((*patch_line != '-') && (*patch_line != '+') |
| + | && (*patch_line != ' ') |
| + | ) { |
| + | break; /* End of hunk */ |
| + | } |
| + | if (*patch_line != '+') { /* '-', ' ' or '\n' */ |
| char *src_line = NULL; | |
| + | if (src_cur_line == src_last_line) |
| + | break; |
| if (src_stream) { | |
| src_line = xmalloc_fgets(src_stream); | |
| if (src_line) { | |
| @@ -188,26 +194,19 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| free(src_line); | |
| if (diff) src_line = NULL; | |
| } | |
| - | if (!src_line) { |
| - | bb_error_msg("hunk #%d FAILED at %d", hunk_count, hunk_offset_start); |
| - | hunk_error = 1; |
| - | break; |
| - | } |
| } | |
| - | if (*patch_line == ' ') { |
| - | fputs(patch_line + 1, dst_stream); |
| - | dest_cur_line++; |
| + | if (!src_line) { |
| + | bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); |
| + | bad_hunk_count++; |
| + | break; |
| + | } |
| + | if (*patch_line == '-') { |
| + | continue; |
| } | |
| - | } else if (*patch_line == '+') { |
| - | fputs(patch_line + 1, dst_stream); |
| - | dest_cur_line++; |
| - | } else { |
| - | break; |
| } | |
| + | fputs(patch_line + 1, dst_stream); |
| + | dest_cur_line++; |
| } /* end of while loop handling one hunk */ | |
| - | if (hunk_error) { |
| - | bad_hunk_count++; |
| - | } |
| } /* end of while loop handling one file */ | |
| /* Cleanup last patched file */ | |
| @@ -217,9 +216,7 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| if (src_stream) { | |
| fclose(src_stream); | |
| } | |
| - | if (dst_stream) { |
| - | fclose(dst_stream); |
| - | } |
| + | fclose(dst_stream); |
| if (bad_hunk_count) { | |
| ret = 1; | |
| bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); | |
| @@ -232,11 +229,12 @@ int patch_main(int argc ATTRIBUTE_UNUSED, char **argv) | |
| if ((dest_cur_line == 0) || (dest_beg_line == 0)) { | |
| /* The new patched file is empty, remove it */ | |
| xunlink(new_filename); | |
| - | if (strcmp(new_filename, original_filename) != 0) |
| - | xunlink(original_filename); |
| + | /* original_filename and new_filename may be the same file */ |
| + | unlink(original_filename); |
| } | |
| } | |
| } /* end of "while there are patch lines" */ | |
| + | quit: |
| /* 0 = SUCCESS | |
| * 1 = Some hunks failed | |