commit 13e2caa3edcc68a62e29b4d5503254cd5bf80b2b from: Stefan Sperling date: Sat Oct 17 14:27:14 2020 UTC add support for showing function prototypes in unidiff hunk headers commit - 5ed6e4d2a7519005ddb8c8b7f47a02f6085df3fe commit + 13e2caa3edcc68a62e29b4d5503254cd5bf80b2b blob - 0bcda3a003c8741c8ea2e2801503387eb993bd12 blob + 6bd48428c4f92c5ed7c7d1695af2f866b953cefb --- diff/diff.c +++ diff/diff.c @@ -41,15 +41,17 @@ enum diffreg_algo { }; __dead void usage(void); -int diffreg(char *, char *, enum diffreg_algo, bool, int, bool); +int diffreg(char *, char *, enum diffreg_algo, bool, bool, + int, bool); FILE * openfile(const char *, char **, struct stat *); __dead void usage(void) { fprintf(stderr, - "usage: %s [-PQTwe] [-U n] file1 file2\n" + "usage: %s [-pPQTwe] [-U n] file1 file2\n" "\n" + " -p Show function prototypes in hunk headers\n" " -P Use Patience Diff (slower but often nicer)\n" " -Q Use forward-Myers for small files, otherwise Patience\n" " -T Trivial algo: detect similar start and end only\n" @@ -65,12 +67,16 @@ main(int argc, char *argv[]) { int ch, rc; bool ignore_whitespace = false; + bool show_function_prototypes = false; bool edscript = false; int context_lines = 3; enum diffreg_algo algo = DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE; - while ((ch = getopt(argc, argv, "PQTwU:e")) != -1) { + while ((ch = getopt(argc, argv, "pPQTwU:e")) != -1) { switch (ch) { + case 'p': + show_function_prototypes = true; + break; case 'P': algo = DIFFREG_ALGO_PATIENCE; break; @@ -101,7 +107,7 @@ main(int argc, char *argv[]) usage(); rc = diffreg(argv[0], argv[1], algo, ignore_whitespace, - context_lines, edscript); + show_function_prototypes, context_lines, edscript); if (rc != DIFF_RC_OK) { fprintf(stderr, "diff: %s\n", strerror(rc)); return 1; @@ -173,7 +179,7 @@ const struct diff_config diff_config_no_algo = { int diffreg(char *file1, char *file2, enum diffreg_algo algo, bool ignore_whitespace, - int context_lines, bool edscript) + bool show_function_prototypes, int context_lines, bool edscript) { char *str1, *str2; FILE *f1, *f2; @@ -208,6 +214,8 @@ diffreg(char *file1, char *file2, enum diffreg_algo al if (ignore_whitespace) diff_flags |= DIFF_FLAG_IGNORE_WHITESPACE; + if (show_function_prototypes) + diff_flags |= DIFF_FLAG_SHOW_PROTOTYPES; result = diff_main(cfg, f1, str1, st1.st_size, f2, str2, st2.st_size, diff_flags); blob - f49a6893b6847f02d5127764222375f1184d051d blob + 99669105d130b9e49ecf3ba09743e0e2c8b1e031 --- include/diff_main.h +++ include/diff_main.h @@ -51,6 +51,7 @@ struct diff_data { }; #define DIFF_FLAG_IGNORE_WHITESPACE 0x00000001 +#define DIFF_FLAG_SHOW_PROTOTYPES 0x00000002 void diff_data_free(struct diff_data *diff_data); blob - f48c869ab05318ba318a42e11631e120cedb7cb6 blob + e4d0d0f911a91395f8dd56ae7de181ff081cfbdf --- lib/diff_internal.h +++ lib/diff_internal.h @@ -115,6 +115,13 @@ diff_atom_same(bool *same, && ((ATOM) - (DIFF_DATA)->atoms.head < (DIFF_DATA)->atoms.len); \ (ATOM)++) +#define diff_data_foreach_atom_backwards_from(FROM, ATOM, DIFF_DATA) \ + for ((ATOM) = (FROM); \ + (ATOM) \ + && ((ATOM) >= (DIFF_DATA)->atoms.head) \ + && ((ATOM) - (DIFF_DATA)->atoms.head >= 0); \ + (ATOM)--) + /* A diff chunk represents a set of atoms on the left and/or a set of atoms on * the right. * @@ -222,6 +229,9 @@ int diff_output_lines(struct diff_output_info *output_ int diff_output_trailing_newline_msg(struct diff_output_info *outinfo, FILE *dest, const struct diff_chunk *c); +int diff_output_match_function_prototype(char **prototype, + const struct diff_result *result, + const struct diff_chunk_context *cc); struct diff_output_info *diff_output_info_alloc(void); blob - 8832026c2c75b90807d7a10e032484e14cc4efd6 blob + 5101e49206dbcf9bfcd8df71242aec39ed8f57a0 --- lib/diff_output.c +++ lib/diff_output.c @@ -15,11 +15,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include #include #include +#include #include #include @@ -233,6 +235,57 @@ diff_output_trailing_newline_msg(struct diff_output_in return DIFF_RC_OK; } +static bool +is_function_prototype(const char *buf) +{ + return isalpha(buf[0]) || buf[0] == '_' || buf[0] == '$'; +} + +#define FUNCTION_CONTEXT_SIZE 55 + +int +diff_output_match_function_prototype(char **prototype, + const struct diff_result *result, + const struct diff_chunk_context *cc) +{ + struct diff_atom *start_atom, *atom; + const struct diff_data *data; + unsigned char buf[FUNCTION_CONTEXT_SIZE]; + int rc, i; + + *prototype = NULL; + + if (result->left.atoms.len > 0) { + data = &result->left; + start_atom = &data->atoms.head[cc->left.start]; + } else if (result->right.atoms.len > 0) { + data = &result->right; + start_atom = &data->atoms.head[cc->right.start]; + } else + return DIFF_RC_OK; + + diff_data_foreach_atom_backwards_from(start_atom, atom, data) { + for (i = 0; i < atom->len && i < sizeof(buf) - 1; i++) { + unsigned int ch; + rc = get_atom_byte(&ch, atom, i); + if (rc) + return rc; + if (ch == '\n') + break; + buf[i] = ch; + } + buf[i] = '\0'; + if (is_function_prototype(buf)) { + *prototype = strdup(buf); + if (*prototype == NULL) + return ENOMEM; + return DIFF_RC_OK; + } + } + + return DIFF_RC_OK; +} + struct diff_output_info * diff_output_info_alloc(void) { blob - a0dba87608e0c39d9e91584b1864e08f921d39d3 blob + 5afb38442065c67a00db9ee4ff61c2348c491507 --- lib/diff_output_unidiff.c +++ lib/diff_output_unidiff.c @@ -200,11 +200,12 @@ output_unidiff_chunk(struct diff_output_info *outinfo, struct diff_output_unidiff_state *state, const struct diff_input_info *info, const struct diff_result *result, - bool print_header, + bool print_header, bool show_function_prototypes, const struct diff_chunk_context *cc) { int rc, left_start, left_len, right_start, right_len; off_t outoff = 0, *offp; + char *prototype = NULL; if (diff_range_empty(&cc->left) && diff_range_empty(&cc->right)) return DIFF_RC_OK; @@ -255,20 +256,36 @@ output_unidiff_chunk(struct diff_output_info *outinfo, right_start = cc->right.start; else right_start = cc->right.start + 1; + + if (show_function_prototypes) { + rc = diff_output_match_function_prototype(&prototype, + result, cc); + if (rc) + return rc; + } if (left_len == 1 && right_len == 1) { - rc = fprintf(dest, "@@ -%d +%d @@\n", - left_start, right_start); + rc = fprintf(dest, "@@ -%d +%d @@%s%s\n", + left_start, right_start, + prototype ? " " : "", + prototype ? : ""); } else if (left_len == 1 && right_len != 1) { - rc = fprintf(dest, "@@ -%d +%d,%d @@\n", - left_start, right_start, right_len); + rc = fprintf(dest, "@@ -%d +%d,%d @@%s%s\n", + left_start, right_start, right_len, + prototype ? " " : "", + prototype ? : ""); } else if (left_len != 1 && right_len == 1) { - rc = fprintf(dest, "@@ -%d,%d +%d @@\n", - left_start, left_len, right_start); + rc = fprintf(dest, "@@ -%d,%d +%d @@%s%s\n", + left_start, left_len, right_start, + prototype ? " " : "", + prototype ? : ""); } else { - rc = fprintf(dest, "@@ -%d,%d +%d,%d @@\n", - left_start, left_len, right_start, right_len); + rc = fprintf(dest, "@@ -%d,%d +%d,%d @@%s%s\n", + left_start, left_len, right_start, right_len, + prototype ? " " : "", + prototype ? : ""); } + free(prototype); if (rc < 0) return errno; if (outinfo) { @@ -352,6 +369,9 @@ diff_output_unidiff_chunk(struct diff_output_info **ou const struct diff_chunk_context *cc) { struct diff_output_info *outinfo = NULL; + int flags = (result->left.root->diff_flags | + result->right.root->diff_flags); + bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES); if (output_info) { *output_info = diff_output_info_alloc(); @@ -361,7 +381,7 @@ diff_output_unidiff_chunk(struct diff_output_info **ou } return output_unidiff_chunk(outinfo, dest, state, info, - result, false, cc); + result, false, show_function_prototypes, cc); } int @@ -373,6 +393,9 @@ diff_output_unidiff(struct diff_output_info **output_i struct diff_output_unidiff_state *state; struct diff_chunk_context cc = {}; struct diff_output_info *outinfo = NULL; + int flags = (result->left.root->diff_flags | + result->right.root->diff_flags); + bool show_function_prototypes = (flags & DIFF_FLAG_SHOW_PROTOTYPES); int i; if (!result) @@ -461,7 +484,7 @@ diff_output_unidiff(struct diff_output_info **output_i " print left %d-%d right %d-%d\n", cc.left.start, cc.left.end, cc.right.start, cc.right.end); output_unidiff_chunk(outinfo, dest, state, info, result, - true, &cc); + true, show_function_prototypes, &cc); cc = next; debug("new unprinted chunk is left %d-%d right %d-%d\n", cc.left.start, cc.left.end, cc.right.start, cc.right.end); @@ -469,7 +492,7 @@ diff_output_unidiff(struct diff_output_info **output_i if (!diff_chunk_context_empty(&cc)) output_unidiff_chunk(outinfo, dest, state, info, result, - true, &cc); + true, show_function_prototypes, &cc); diff_output_unidiff_state_free(state); return DIFF_RC_OK; }