1*75f6d617Schristos /* $NetBSD: diff.h,v 1.1.1.1 2016/01/13 03:15:30 christos Exp $ */ 2*75f6d617Schristos 3*75f6d617Schristos /* Shared definitions for GNU DIFF 4*75f6d617Schristos 5*75f6d617Schristos Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998, 2001, 6*75f6d617Schristos 2002 Free Software Foundation, Inc. 7*75f6d617Schristos 8*75f6d617Schristos This file is part of GNU DIFF. 9*75f6d617Schristos 10*75f6d617Schristos GNU DIFF is free software; you can redistribute it and/or modify 11*75f6d617Schristos it under the terms of the GNU General Public License as published by 12*75f6d617Schristos the Free Software Foundation; either version 2, or (at your option) 13*75f6d617Schristos any later version. 14*75f6d617Schristos 15*75f6d617Schristos GNU DIFF is distributed in the hope that it will be useful, 16*75f6d617Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 17*75f6d617Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*75f6d617Schristos GNU General Public License for more details. 19*75f6d617Schristos 20*75f6d617Schristos You should have received a copy of the GNU General Public License 21*75f6d617Schristos along with this program; see the file COPYING. 22*75f6d617Schristos If not, write to the Free Software Foundation, 23*75f6d617Schristos 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 24*75f6d617Schristos 25*75f6d617Schristos #include "system.h" 26*75f6d617Schristos #include <stdio.h> 27*75f6d617Schristos 28*75f6d617Schristos #define TAB_WIDTH 8 29*75f6d617Schristos 30*75f6d617Schristos /* What kind of changes a hunk contains. */ 31*75f6d617Schristos enum changes 32*75f6d617Schristos { 33*75f6d617Schristos /* No changes: lines common to both files. */ 34*75f6d617Schristos UNCHANGED, 35*75f6d617Schristos 36*75f6d617Schristos /* Deletes only: lines taken from just the first file. */ 37*75f6d617Schristos OLD, 38*75f6d617Schristos 39*75f6d617Schristos /* Inserts only: lines taken from just the second file. */ 40*75f6d617Schristos NEW, 41*75f6d617Schristos 42*75f6d617Schristos /* Both deletes and inserts: a hunk containing both old and new lines. */ 43*75f6d617Schristos CHANGED 44*75f6d617Schristos }; 45*75f6d617Schristos 46*75f6d617Schristos /* Variables for command line options */ 47*75f6d617Schristos 48*75f6d617Schristos #ifndef GDIFF_MAIN 49*75f6d617Schristos # define XTERN extern 50*75f6d617Schristos #else 51*75f6d617Schristos # define XTERN 52*75f6d617Schristos #endif 53*75f6d617Schristos 54*75f6d617Schristos enum output_style 55*75f6d617Schristos { 56*75f6d617Schristos /* No output style specified. */ 57*75f6d617Schristos OUTPUT_UNSPECIFIED, 58*75f6d617Schristos 59*75f6d617Schristos /* Default output style. */ 60*75f6d617Schristos OUTPUT_NORMAL, 61*75f6d617Schristos 62*75f6d617Schristos /* Output the differences with lines of context before and after (-c). */ 63*75f6d617Schristos OUTPUT_CONTEXT, 64*75f6d617Schristos 65*75f6d617Schristos /* Output the differences in a unified context diff format (-u). */ 66*75f6d617Schristos OUTPUT_UNIFIED, 67*75f6d617Schristos 68*75f6d617Schristos /* Output the differences as commands suitable for `ed' (-e). */ 69*75f6d617Schristos OUTPUT_ED, 70*75f6d617Schristos 71*75f6d617Schristos /* Output the diff as a forward ed script (-f). */ 72*75f6d617Schristos OUTPUT_FORWARD_ED, 73*75f6d617Schristos 74*75f6d617Schristos /* Like -f, but output a count of changed lines in each "command" (-n). */ 75*75f6d617Schristos OUTPUT_RCS, 76*75f6d617Schristos 77*75f6d617Schristos /* Output merged #ifdef'd file (-D). */ 78*75f6d617Schristos OUTPUT_IFDEF, 79*75f6d617Schristos 80*75f6d617Schristos /* Output sdiff style (-y). */ 81*75f6d617Schristos OUTPUT_SDIFF 82*75f6d617Schristos }; 83*75f6d617Schristos 84*75f6d617Schristos /* True for output styles that are robust, 85*75f6d617Schristos i.e. can handle a file that ends in a non-newline. */ 86*75f6d617Schristos #define ROBUST_OUTPUT_STYLE(S) ((S) != OUTPUT_ED && (S) != OUTPUT_FORWARD_ED) 87*75f6d617Schristos 88*75f6d617Schristos XTERN enum output_style output_style; 89*75f6d617Schristos 90*75f6d617Schristos /* Nonzero if output cannot be generated for identical files. */ 91*75f6d617Schristos XTERN bool no_diff_means_no_output; 92*75f6d617Schristos 93*75f6d617Schristos /* Number of lines of context to show in each set of diffs. 94*75f6d617Schristos This is zero when context is not to be shown. */ 95*75f6d617Schristos XTERN lin context; 96*75f6d617Schristos 97*75f6d617Schristos /* Consider all files as text files (-a). 98*75f6d617Schristos Don't interpret codes over 0177 as implying a "binary file". */ 99*75f6d617Schristos XTERN bool text; 100*75f6d617Schristos 101*75f6d617Schristos /* Number of lines to keep in identical prefix and suffix. */ 102*75f6d617Schristos XTERN lin horizon_lines; 103*75f6d617Schristos 104*75f6d617Schristos /* The significance of white space during comparisons. */ 105*75f6d617Schristos XTERN enum 106*75f6d617Schristos { 107*75f6d617Schristos /* All white space is significant (the default). */ 108*75f6d617Schristos IGNORE_NO_WHITE_SPACE, 109*75f6d617Schristos 110*75f6d617Schristos /* Ignore changes due to tab expansion (-E). */ 111*75f6d617Schristos IGNORE_TAB_EXPANSION, 112*75f6d617Schristos 113*75f6d617Schristos /* Ignore changes in horizontal white space (-b). */ 114*75f6d617Schristos IGNORE_SPACE_CHANGE, 115*75f6d617Schristos 116*75f6d617Schristos /* Ignore all horizontal white space (-w). */ 117*75f6d617Schristos IGNORE_ALL_SPACE 118*75f6d617Schristos } ignore_white_space; 119*75f6d617Schristos 120*75f6d617Schristos /* Ignore changes that affect only blank lines (-B). */ 121*75f6d617Schristos XTERN bool ignore_blank_lines; 122*75f6d617Schristos 123*75f6d617Schristos /* Files can be compared byte-by-byte, as if they were binary. 124*75f6d617Schristos This depends on various options. */ 125*75f6d617Schristos XTERN bool files_can_be_treated_as_binary; 126*75f6d617Schristos 127*75f6d617Schristos /* Ignore differences in case of letters (-i). */ 128*75f6d617Schristos XTERN bool ignore_case; 129*75f6d617Schristos 130*75f6d617Schristos /* Ignore differences in case of letters in file names. */ 131*75f6d617Schristos XTERN bool ignore_file_name_case; 132*75f6d617Schristos 133*75f6d617Schristos /* File labels for `-c' output headers (--label). */ 134*75f6d617Schristos XTERN char *file_label[2]; 135*75f6d617Schristos 136*75f6d617Schristos /* Regexp to identify function-header lines (-F). */ 137*75f6d617Schristos XTERN struct re_pattern_buffer function_regexp; 138*75f6d617Schristos 139*75f6d617Schristos /* Ignore changes that affect only lines matching this regexp (-I). */ 140*75f6d617Schristos XTERN struct re_pattern_buffer ignore_regexp; 141*75f6d617Schristos 142*75f6d617Schristos /* Say only whether files differ, not how (-q). */ 143*75f6d617Schristos XTERN bool brief; 144*75f6d617Schristos 145*75f6d617Schristos /* Expand tabs in the output so the text lines up properly 146*75f6d617Schristos despite the characters added to the front of each line (-t). */ 147*75f6d617Schristos XTERN bool expand_tabs; 148*75f6d617Schristos 149*75f6d617Schristos /* Use a tab in the output, rather than a space, before the text of an 150*75f6d617Schristos input line, so as to keep the proper alignment in the input line 151*75f6d617Schristos without changing the characters in it (-T). */ 152*75f6d617Schristos XTERN bool initial_tab; 153*75f6d617Schristos 154*75f6d617Schristos /* Remove trailing carriage returns from input. */ 155*75f6d617Schristos XTERN bool strip_trailing_cr; 156*75f6d617Schristos 157*75f6d617Schristos /* In directory comparison, specify file to start with (-S). 158*75f6d617Schristos This is used for resuming an aborted comparison. 159*75f6d617Schristos All file names less than this name are ignored. */ 160*75f6d617Schristos XTERN char const *starting_file; 161*75f6d617Schristos 162*75f6d617Schristos /* Pipe each file's output through pr (-l). */ 163*75f6d617Schristos XTERN bool paginate; 164*75f6d617Schristos 165*75f6d617Schristos /* Line group formats for unchanged, old, new, and changed groups. */ 166*75f6d617Schristos XTERN char const *group_format[CHANGED + 1]; 167*75f6d617Schristos 168*75f6d617Schristos /* Line formats for unchanged, old, and new lines. */ 169*75f6d617Schristos XTERN char const *line_format[NEW + 1]; 170*75f6d617Schristos 171*75f6d617Schristos /* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */ 172*75f6d617Schristos XTERN bool sdiff_merge_assist; 173*75f6d617Schristos 174*75f6d617Schristos /* Tell OUTPUT_SDIFF to show only the left version of common lines. */ 175*75f6d617Schristos XTERN bool left_column; 176*75f6d617Schristos 177*75f6d617Schristos /* Tell OUTPUT_SDIFF to not show common lines. */ 178*75f6d617Schristos XTERN bool suppress_common_lines; 179*75f6d617Schristos 180*75f6d617Schristos /* The half line width and column 2 offset for OUTPUT_SDIFF. */ 181*75f6d617Schristos XTERN unsigned int sdiff_half_width; 182*75f6d617Schristos XTERN unsigned int sdiff_column2_offset; 183*75f6d617Schristos 184*75f6d617Schristos /* String containing all the command options diff received, 185*75f6d617Schristos with spaces between and at the beginning but none at the end. 186*75f6d617Schristos If there were no options given, this string is empty. */ 187*75f6d617Schristos XTERN char *switch_string; 188*75f6d617Schristos 189*75f6d617Schristos /* Use heuristics for better speed with large files with a small 190*75f6d617Schristos density of changes. */ 191*75f6d617Schristos XTERN bool speed_large_files; 192*75f6d617Schristos 193*75f6d617Schristos /* Patterns that match file names to be excluded. */ 194*75f6d617Schristos XTERN struct exclude *excluded; 195*75f6d617Schristos 196*75f6d617Schristos /* Don't discard lines. This makes things slower (sometimes much 197*75f6d617Schristos slower) but will find a guaranteed minimal set of changes. */ 198*75f6d617Schristos XTERN bool minimal; 199*75f6d617Schristos 200*75f6d617Schristos /* Name of program the user invoked (for error messages). */ 201*75f6d617Schristos XTERN char *program_name; 202*75f6d617Schristos 203*75f6d617Schristos /* The strftime format to use for time strings. */ 204*75f6d617Schristos XTERN char const *time_format; 205*75f6d617Schristos 206*75f6d617Schristos /* The result of comparison is an "edit script": a chain of `struct change'. 207*75f6d617Schristos Each `struct change' represents one place where some lines are deleted 208*75f6d617Schristos and some are inserted. 209*75f6d617Schristos 210*75f6d617Schristos LINE0 and LINE1 are the first affected lines in the two files (origin 0). 211*75f6d617Schristos DELETED is the number of lines deleted here from file 0. 212*75f6d617Schristos INSERTED is the number of lines inserted here in file 1. 213*75f6d617Schristos 214*75f6d617Schristos If DELETED is 0 then LINE0 is the number of the line before 215*75f6d617Schristos which the insertion was done; vice versa for INSERTED and LINE1. */ 216*75f6d617Schristos 217*75f6d617Schristos struct change 218*75f6d617Schristos { 219*75f6d617Schristos struct change *link; /* Previous or next edit command */ 220*75f6d617Schristos lin inserted; /* # lines of file 1 changed here. */ 221*75f6d617Schristos lin deleted; /* # lines of file 0 changed here. */ 222*75f6d617Schristos lin line0; /* Line number of 1st deleted line. */ 223*75f6d617Schristos lin line1; /* Line number of 1st inserted line. */ 224*75f6d617Schristos bool ignore; /* Flag used in context.c. */ 225*75f6d617Schristos }; 226*75f6d617Schristos 227*75f6d617Schristos /* Structures that describe the input files. */ 228*75f6d617Schristos 229*75f6d617Schristos /* Data on one input file being compared. */ 230*75f6d617Schristos 231*75f6d617Schristos struct file_data { 232*75f6d617Schristos int desc; /* File descriptor */ 233*75f6d617Schristos char const *name; /* File name */ 234*75f6d617Schristos struct stat stat; /* File status */ 235*75f6d617Schristos 236*75f6d617Schristos /* Buffer in which text of file is read. */ 237*75f6d617Schristos word *buffer; 238*75f6d617Schristos 239*75f6d617Schristos /* Allocated size of buffer, in bytes. Always a multiple of 240*75f6d617Schristos sizeof *buffer. */ 241*75f6d617Schristos size_t bufsize; 242*75f6d617Schristos 243*75f6d617Schristos /* Number of valid bytes now in the buffer. */ 244*75f6d617Schristos size_t buffered; 245*75f6d617Schristos 246*75f6d617Schristos /* Array of pointers to lines in the file. */ 247*75f6d617Schristos char const **linbuf; 248*75f6d617Schristos 249*75f6d617Schristos /* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines. 250*75f6d617Schristos linebuf[linbuf_base ... buffered_lines - 1] are possibly differing. 251*75f6d617Schristos linebuf[linbuf_base ... valid_lines - 1] contain valid data. 252*75f6d617Schristos linebuf[linbuf_base ... alloc_lines - 1] are allocated. */ 253*75f6d617Schristos lin linbuf_base, buffered_lines, valid_lines, alloc_lines; 254*75f6d617Schristos 255*75f6d617Schristos /* Pointer to end of prefix of this file to ignore when hashing. */ 256*75f6d617Schristos char const *prefix_end; 257*75f6d617Schristos 258*75f6d617Schristos /* Count of lines in the prefix. 259*75f6d617Schristos There are this many lines in the file before linbuf[0]. */ 260*75f6d617Schristos lin prefix_lines; 261*75f6d617Schristos 262*75f6d617Schristos /* Pointer to start of suffix of this file to ignore when hashing. */ 263*75f6d617Schristos char const *suffix_begin; 264*75f6d617Schristos 265*75f6d617Schristos /* Vector, indexed by line number, containing an equivalence code for 266*75f6d617Schristos each line. It is this vector that is actually compared with that 267*75f6d617Schristos of another file to generate differences. */ 268*75f6d617Schristos lin *equivs; 269*75f6d617Schristos 270*75f6d617Schristos /* Vector, like the previous one except that 271*75f6d617Schristos the elements for discarded lines have been squeezed out. */ 272*75f6d617Schristos lin *undiscarded; 273*75f6d617Schristos 274*75f6d617Schristos /* Vector mapping virtual line numbers (not counting discarded lines) 275*75f6d617Schristos to real ones (counting those lines). Both are origin-0. */ 276*75f6d617Schristos lin *realindexes; 277*75f6d617Schristos 278*75f6d617Schristos /* Total number of nondiscarded lines. */ 279*75f6d617Schristos lin nondiscarded_lines; 280*75f6d617Schristos 281*75f6d617Schristos /* Vector, indexed by real origin-0 line number, 282*75f6d617Schristos containing TRUE for a line that is an insertion or a deletion. 283*75f6d617Schristos The results of comparison are stored here. */ 284*75f6d617Schristos bool *changed; 285*75f6d617Schristos 286*75f6d617Schristos /* 1 if file ends in a line with no final newline. */ 287*75f6d617Schristos bool missing_newline; 288*75f6d617Schristos 289*75f6d617Schristos /* 1 if at end of file. */ 290*75f6d617Schristos bool eof; 291*75f6d617Schristos 292*75f6d617Schristos /* 1 more than the maximum equivalence value used for this or its 293*75f6d617Schristos sibling file. */ 294*75f6d617Schristos lin equiv_max; 295*75f6d617Schristos }; 296*75f6d617Schristos 297*75f6d617Schristos /* The file buffer, considered as an array of bytes rather than 298*75f6d617Schristos as an array of words. */ 299*75f6d617Schristos #define FILE_BUFFER(f) ((char *) (f)->buffer) 300*75f6d617Schristos 301*75f6d617Schristos /* Data on two input files being compared. */ 302*75f6d617Schristos 303*75f6d617Schristos struct comparison 304*75f6d617Schristos { 305*75f6d617Schristos struct file_data file[2]; 306*75f6d617Schristos struct comparison const *parent; /* parent, if a recursive comparison */ 307*75f6d617Schristos }; 308*75f6d617Schristos 309*75f6d617Schristos /* Describe the two files currently being compared. */ 310*75f6d617Schristos 311*75f6d617Schristos XTERN struct file_data files[2]; 312*75f6d617Schristos 313*75f6d617Schristos /* Stdio stream to output diffs to. */ 314*75f6d617Schristos 315*75f6d617Schristos XTERN FILE *outfile; 316*75f6d617Schristos 317*75f6d617Schristos /* Declare various functions. */ 318*75f6d617Schristos 319*75f6d617Schristos /* analyze.c */ 320*75f6d617Schristos int diff_2_files (struct comparison *); 321*75f6d617Schristos 322*75f6d617Schristos /* context.c */ 323*75f6d617Schristos void print_context_header (struct file_data[], bool); 324*75f6d617Schristos void print_context_script (struct change *, bool); 325*75f6d617Schristos 326*75f6d617Schristos /* dir.c */ 327*75f6d617Schristos int diff_dirs (struct comparison const *, int (*) (struct comparison const *, char const *, char const *)); 328*75f6d617Schristos 329*75f6d617Schristos /* ed.c */ 330*75f6d617Schristos void print_ed_script (struct change *); 331*75f6d617Schristos void pr_forward_ed_script (struct change *); 332*75f6d617Schristos 333*75f6d617Schristos /* ifdef.c */ 334*75f6d617Schristos void print_ifdef_script (struct change *); 335*75f6d617Schristos 336*75f6d617Schristos /* io.c */ 337*75f6d617Schristos void file_block_read (struct file_data *, size_t); 338*75f6d617Schristos bool read_files (struct file_data[], bool); 339*75f6d617Schristos 340*75f6d617Schristos /* normal.c */ 341*75f6d617Schristos void print_normal_script (struct change *); 342*75f6d617Schristos 343*75f6d617Schristos /* rcs.c */ 344*75f6d617Schristos void print_rcs_script (struct change *); 345*75f6d617Schristos 346*75f6d617Schristos /* side.c */ 347*75f6d617Schristos void print_sdiff_script (struct change *); 348*75f6d617Schristos 349*75f6d617Schristos /* util.c */ 350*75f6d617Schristos extern char const change_letter[4]; 351*75f6d617Schristos extern char const pr_program[]; 352*75f6d617Schristos char *concat (char const *, char const *, char const *); 353*75f6d617Schristos char *dir_file_pathname (char const *, char const *); 354*75f6d617Schristos bool lines_differ (char const *, char const *); 355*75f6d617Schristos lin translate_line_number (struct file_data const *, lin); 356*75f6d617Schristos struct change *find_change (struct change *); 357*75f6d617Schristos struct change *find_reverse_change (struct change *); 358*75f6d617Schristos void *zalloc (size_t); 359*75f6d617Schristos enum changes analyze_hunk (struct change *, lin *, lin *, lin *, lin *); 360*75f6d617Schristos void begin_output (void); 361*75f6d617Schristos void debug_script (struct change *); 362*75f6d617Schristos void fatal (char const *) __attribute__((noreturn)); 363*75f6d617Schristos void finish_output (void); 364*75f6d617Schristos void message (char const *, char const *, char const *); 365*75f6d617Schristos void message5 (char const *, char const *, char const *, char const *, char const *); 366*75f6d617Schristos void output_1_line (char const *, char const *, char const *, char const *); 367*75f6d617Schristos void perror_with_name (char const *); 368*75f6d617Schristos void pfatal_with_name (char const *) __attribute__((noreturn)); 369*75f6d617Schristos void print_1_line (char const *, char const * const *); 370*75f6d617Schristos void print_message_queue (void); 371*75f6d617Schristos void print_number_range (char, struct file_data *, lin, lin); 372*75f6d617Schristos void print_script (struct change *, struct change * (*) (struct change *), void (*) (struct change *)); 373*75f6d617Schristos void setup_output (char const *, char const *, bool); 374*75f6d617Schristos void translate_range (struct file_data const *, lin, lin, long *, long *); 375*75f6d617Schristos 376*75f6d617Schristos /* version.c */ 377*75f6d617Schristos extern char const version_string[]; 378