#include "system.h" #include #include #include #include "keccak.h" /* What kind of changes a hunk contains. */ enum changes { /* No changes: lines common to both files. */ UNCHANGED, /* Deletes only: lines taken from just the first file. */ OLD, /* Inserts only: lines taken from just the second file. */ NEW, /* Both deletes and inserts: a hunk containing both old and new lines. */ CHANGED }; /* Variables for command line options */ #ifndef GDIFF_MAIN # define XTERN extern #else # define XTERN #endif /* Number of lines of context to show in each set of diffs. This is zero when context is not to be shown. */ XTERN lin context; /* Consider all files as text files (-a). Don't interpret codes over 0177 as implying a "binary file". */ XTERN bool text; /* Number of lines to keep in identical prefix and suffix. */ XTERN lin horizon_lines; /* Files can be compared byte-by-byte, as if they were binary. This depends on various options. */ XTERN bool files_can_be_treated_as_binary; /* File labels for |-c| output headers (|--label|). */ XTERN char *file_label[2]; /* Say only whether files differ, not how (|-q|). */ XTERN bool brief; /* Do not output an initial space or tab before the text of an empty line. */ XTERN bool suppress_blank_empty; /* In directory comparison, specify file to start with (|-S|). This is used for resuming an aborted comparison. All file names less than this name are ignored. */ XTERN char const *starting_file; /* String containing all the command options diff received, with spaces between and at the beginning but none at the end. If there were no options given, this string is empty. */ XTERN char *switch_string; /* Use heuristics for better speed with large files with a small density of changes. */ XTERN bool speed_large_files; /* Don't discard lines. This makes things slower (sometimes much slower) but will find a guaranteed minimal set of changes. */ XTERN bool minimal; /* The result of comparison is an ``edit script'': a chain of |struct change|. Each |struct change| represents one place where some lines are deleted and some are inserted. |line0| and |line1| are the first affected lines in the two files (origin 0). |deleted| is the number of lines deleted here from file 0. |inserted| is the number of lines inserted here in file 1. If |deleted| is 0 then |line0| is the number of the line before which the insertion was done; vice versa for |inserted| and |line1|. */ struct change { struct change *link; /* Previous or next edit command */ lin inserted; /* \# lines of file 1 changed here. */ lin deleted; /* \# lines of file 0 changed here. */ lin line0; /* Line number of 1st deleted line. */ lin line1; /* Line number of 1st inserted line. */ bool ignore; /* Flag used in |context.c|. */ }; /* Structures that describe the input files. */ /* Data on one input file being compared. */ struct file_data { int desc; /* File descriptor */ char const *name; /* File name */ struct stat stat; /* File status */ /* Buffer in which text of file is read. */ word *buffer; /* Allocated size of buffer, in bytes. Always a multiple of sizeof |*buffer|. */ size_t bufsize; /* Number of valid bytes now in the buffer. */ size_t buffered; /* Array of pointers to lines in the file. */ char const **linbuf; /* |linbuf_base <= buffered_lines <= valid_lines <= alloc_lines|. |linebuf[linbuf_base ... buffered_lines - 1]| are possibly differing. |linebuf[linbuf_base ... valid_lines - 1]| contain valid data. |linebuf[linbuf_base ... alloc_lines - 1]| are allocated. */ lin linbuf_base, buffered_lines, valid_lines, alloc_lines; /* Pointer to end of prefix of this file to ignore when hashing. */ char const *prefix_end; /* Count of lines in the prefix. There are this many lines in the file before |linbuf[0]|. */ lin prefix_lines; /* Pointer to start of suffix of this file to ignore when hashing. */ char const *suffix_begin; /* Vector, indexed by line number, containing an equivalence code for each line. It is this vector that is actually compared with that of another file to generate differences. */ lin *equivs; /* Vector, like the previous one except that the elements for discarded lines have been squeezed out. */ lin *undiscarded; /* Vector mapping virtual line numbers (not counting discarded lines) to real ones (counting those lines). Both are $origin-0$. */ lin *realindexes; /* Total number of nondiscarded lines. */ lin nondiscarded_lines; /* Vector, indexed by real $origin-0$ line number, containing 1 for a line that is an insertion or a deletion. The results of comparison are stored here. */ char *changed; /* 1 if file ends in a line with no final newline. */ bool missing_newline; /* 1 if at end of file. */ bool eof; /* 1 more than the maximum equivalence value used for this or its sibling file. */ lin equiv_max; /* keccak context */ void *hash_context; uint64_t hash[8]; }; /* The file buffer, considered as an array of bytes rather than as an array of words. */ #define FILE_BUFFER(f) ((char *) (f)->buffer) /* Data on two input files being compared. */ struct comparison { struct file_data file[2]; struct comparison const *parent; /* parent, if a recursive comparison */ }; /* Describe the two files currently being compared. */ XTERN struct file_data files[2]; /* Stdio stream to output diffs to. */ XTERN FILE *outfile; /* Declare various functions. */ /* analyze.c */ extern int diff_2_files(struct comparison *); /* context.c */ extern void print_context_header(struct file_data[], char const *const *); extern void print_context_script(struct change *); /* dir.c */ extern int diff_dirs(struct comparison const *, int (*)(struct comparison const *, char const *, char const *)); extern char *find_dir_file_pathname(char const *, char const *); /* diff.h */ extern struct change *find_hunk(struct change *); extern void pr_unidiff_hunk(struct change *); /* io.c */ extern void file_block_read(struct file_data *, size_t); extern bool read_files(struct file_data[], bool); /* util.c */ extern bool lines_differ(char const *, char const *); extern lin translate_line_number(struct file_data const *, lin); extern struct change *find_change(struct change *); extern void *zalloc(size_t); extern enum changes analyze_hunk(struct change *, lin *, lin *, lin *, lin *); extern void begin_output(void); extern void debug_script(struct change *); extern void fatal(char const *) __attribute__((noreturn)); extern void finish_output(void); extern void message(char const *, char const *, char const *); extern void message5(char const *, char const *, char const *, char const *, char const *); extern void output_1_line(char const *, char const *); extern void perror_with_name(char const *); extern void pfatal_with_name(char const *) __attribute__((noreturn)); extern void print_1_line(char const *, char const *const *); extern void print_1_line_nl(char const *, char const *const *, bool); extern void print_script(struct change *); extern void setup_output(char const *, char const *, bool); extern void translate_range(struct file_data const *, lin, lin, printint *, printint *);