1 /* Support routines for GNU DIFF. 2 Copyright (C) 1988, 1989, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc. 3 4 This file is part of GNU DIFF. 5 6 GNU DIFF is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU DIFF is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 */ 17 18 #include "diff.h" 19 20 #if __STDC__ 21 #include <stdarg.h> 22 #else 23 #include <varargs.h> 24 #endif 25 26 #ifndef strerror 27 extern char *strerror (); 28 #endif 29 30 /* Queue up one-line messages to be printed at the end, 31 when -l is specified. Each message is recorded with a `struct msg'. */ 32 33 struct msg 34 { 35 struct msg *next; 36 char const *format; 37 char const *arg1; 38 char const *arg2; 39 char const *arg3; 40 char const *arg4; 41 }; 42 43 /* Head of the chain of queues messages. */ 44 45 static struct msg *msg_chain; 46 47 /* Tail of the chain of queues messages. */ 48 49 static struct msg **msg_chain_end = &msg_chain; 50 51 /* Use when a system call returns non-zero status. 53 TEXT should normally be the file name. */ 54 55 void 56 perror_with_name (text) 57 char const *text; 58 { 59 int e = errno; 60 61 if (callbacks && callbacks->error) 62 (*callbacks->error) ("%s: %s", text, strerror (e)); 63 else 64 { 65 fprintf (stderr, "%s: ", diff_program_name); 66 errno = e; 67 perror (text); 68 } 69 } 70 71 /* Use when a system call returns non-zero status and that is fatal. */ 72 73 void 74 pfatal_with_name (text) 75 char const *text; 76 { 77 int e = errno; 78 print_message_queue (); 79 if (callbacks && callbacks->error) 80 (*callbacks->error) ("%s: %s", text, strerror (e)); 81 else 82 { 83 fprintf (stderr, "%s: ", diff_program_name); 84 errno = e; 85 perror (text); 86 } 87 DIFF_ABORT (2); 88 } 89 90 /* Print an error message from the format-string FORMAT 91 with args ARG1 and ARG2. */ 92 93 void 94 diff_error (format, arg, arg1) 95 char const *format, *arg, *arg1; 96 { 97 if (callbacks && callbacks->error) 98 (*callbacks->error) (format, arg, arg1); 99 else 100 { 101 fprintf (stderr, "%s: ", diff_program_name); 102 fprintf (stderr, format, arg, arg1); 103 fprintf (stderr, "\n"); 104 } 105 } 106 107 /* Print an error message containing the string TEXT, then exit. */ 108 109 void 110 fatal (m) 111 char const *m; 112 { 113 print_message_queue (); 114 diff_error ("%s", m, 0); 115 DIFF_ABORT (2); 116 } 117 118 /* Like printf, except if -l in effect then save the message and print later. 120 This is used for things like "binary files differ" and "Only in ...". */ 121 122 void 123 message (format, arg1, arg2) 124 char const *format, *arg1, *arg2; 125 { 126 message5 (format, arg1, arg2, 0, 0); 127 } 128 129 void 130 message5 (format, arg1, arg2, arg3, arg4) 131 char const *format, *arg1, *arg2, *arg3, *arg4; 132 { 133 if (paginate_flag) 134 { 135 struct msg *new = (struct msg *) xmalloc (sizeof (struct msg)); 136 new->format = format; 137 new->arg1 = concat (arg1, "", ""); 138 new->arg2 = concat (arg2, "", ""); 139 new->arg3 = arg3 ? concat (arg3, "", "") : 0; 140 new->arg4 = arg4 ? concat (arg4, "", "") : 0; 141 new->next = 0; 142 *msg_chain_end = new; 143 msg_chain_end = &new->next; 144 } 145 else 146 { 147 if (sdiff_help_sdiff) 148 write_output (" ", 1); 149 printf_output (format, arg1, arg2, arg3, arg4); 150 } 151 } 152 153 /* Output all the messages that were saved up by calls to `message'. */ 154 155 void 156 print_message_queue () 157 { 158 struct msg *m; 159 160 for (m = msg_chain; m; m = m->next) 161 printf_output (m->format, m->arg1, m->arg2, m->arg3, m->arg4); 162 } 163 164 /* Call before outputting the results of comparing files NAME0 and NAME1 166 to set up OUTFILE, the stdio stream for the output to go to. 167 168 Usually, OUTFILE is just stdout. But when -l was specified 169 we fork off a `pr' and make OUTFILE a pipe to it. 170 `pr' then outputs to our stdout. */ 171 172 static char const *current_name0; 173 static char const *current_name1; 174 static int current_depth; 175 176 static int output_in_progress = 0; 177 178 void 179 setup_output (name0, name1, depth) 180 char const *name0, *name1; 181 int depth; 182 { 183 current_name0 = name0; 184 current_name1 = name1; 185 current_depth = depth; 186 } 187 188 #if HAVE_FORK && defined (PR_PROGRAM) 189 static pid_t pr_pid; 190 #endif 191 192 void 193 begin_output () 194 { 195 char *name; 196 197 if (output_in_progress) 198 return; 199 output_in_progress = 1; 200 201 /* Construct the header of this piece of diff. */ 202 name = xmalloc (strlen (current_name0) + strlen (current_name1) 203 + strlen (switch_string) + 7); 204 /* Posix.2 section 4.17.6.1.1 specifies this format. But there is a 205 bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304): 206 it says that we must print only the last component of the pathnames. 207 This requirement is silly and does not match historical practice. */ 208 sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1); 209 210 if (paginate_flag && callbacks && callbacks->write_output) 211 fatal ("can't paginate when using library callbacks"); 212 213 if (paginate_flag) 214 { 215 /* Make OUTFILE a pipe to a subsidiary `pr'. */ 216 217 #ifdef PR_PROGRAM 218 219 # if HAVE_FORK 220 int pipes[2]; 221 222 if (pipe (pipes) != 0) 223 pfatal_with_name ("pipe"); 224 225 fflush (stdout); 226 227 pr_pid = vfork (); 228 if (pr_pid < 0) 229 pfatal_with_name ("vfork"); 230 231 if (pr_pid == 0) 232 { 233 close (pipes[1]); 234 if (pipes[0] != STDIN_FILENO) 235 { 236 if (dup2 (pipes[0], STDIN_FILENO) < 0) 237 pfatal_with_name ("dup2"); 238 close (pipes[0]); 239 } 240 241 execl (PR_PROGRAM, PR_PROGRAM, "-f", "-h", name, NULL); 242 pfatal_with_name (PR_PROGRAM); 243 } 244 else 245 { 246 close (pipes[0]); 247 outfile = fdopen (pipes[1], "w"); 248 if (!outfile) 249 pfatal_with_name ("fdopen"); 250 } 251 # else /* ! HAVE_FORK */ 252 char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10); 253 char *p; 254 char const *a = name; 255 sprintf (command, "%s -f -h ", PR_PROGRAM); 256 p = command + strlen (command); 257 SYSTEM_QUOTE_ARG (p, a); 258 *p = 0; 259 outfile = popen (command, "w"); 260 if (!outfile) 261 pfatal_with_name (command); 262 free (command); 263 # endif /* ! HAVE_FORK */ 264 #else 265 fatal ("This port does not support the --paginate option to diff."); 266 #endif 267 } 268 else 269 { 270 271 /* If -l was not specified, output the diff straight to `stdout'. */ 272 273 /* If handling multiple files (because scanning a directory), 274 print which files the following output is about. */ 275 if (current_depth > 0) 276 printf_output ("%s\n", name); 277 } 278 279 free (name); 280 281 /* A special header is needed at the beginning of context output. */ 282 switch (output_style) 283 { 284 case OUTPUT_CONTEXT: 285 print_context_header (files, 0); 286 break; 287 288 case OUTPUT_UNIFIED: 289 print_context_header (files, 1); 290 break; 291 292 default: 293 break; 294 } 295 } 296 297 /* Call after the end of output of diffs for one file. 298 If -l was given, close OUTFILE and get rid of the `pr' subfork. */ 299 300 void 301 finish_output () 302 { 303 if (paginate_flag && outfile != 0 && outfile != stdout) 304 { 305 #ifdef PR_PROGRAM 306 int wstatus, w; 307 if (ferror (outfile)) 308 fatal ("write error"); 309 # if ! HAVE_FORK 310 wstatus = pclose (outfile); 311 # else /* HAVE_FORK */ 312 if (fclose (outfile) != 0) 313 pfatal_with_name ("write error"); 314 while ((w = waitpid (pr_pid, &wstatus, 0)) < 0 && errno == EINTR) 315 ; 316 if (w < 0) 317 pfatal_with_name ("waitpid"); 318 # endif /* HAVE_FORK */ 319 if (wstatus != 0) 320 fatal ("subsidiary pr failed"); 321 #else 322 fatal ("internal error in finish_output"); 323 #endif 324 } 325 326 output_in_progress = 0; 327 } 328 329 /* Write something to the output file. */ 330 331 void 332 write_output (text, len) 333 char const *text; 334 size_t len; 335 { 336 if (callbacks && callbacks->write_output) 337 (*callbacks->write_output) (text, len); 338 else if (len == 1) 339 putc (*text, outfile); 340 else 341 fwrite (text, sizeof (char), len, outfile); 342 } 343 344 /* Printf something to the output file. */ 345 346 #if __STDC__ 347 #define VA_START(args, lastarg) va_start(args, lastarg) 348 #else /* ! __STDC__ */ 349 #define VA_START(args, lastarg) va_start(args) 350 #endif /* __STDC__ */ 351 352 void 353 #if __STDC__ 354 printf_output (const char *format, ...) 355 #else 356 printf_output (format, va_alist) 357 char const *format; 358 va_dcl 359 #endif 360 { 361 va_list args; 362 363 VA_START (args, format); 364 if (callbacks && callbacks->write_output) 365 { 366 /* We implement our own limited printf-like functionality (%s, %d, 367 and %c only). Callers who want something fancier can use 368 sprintf. */ 369 const char *p = format; 370 char *q; 371 char *str; 372 int num; 373 int ch; 374 char buf[100]; 375 376 while ((q = strchr (p, '%')) != NULL) 377 { 378 static const char msg[] = 379 "\ninternal error: bad % in printf_output\n"; 380 (*callbacks->write_output) (p, q - p); 381 382 switch (q[1]) 383 { 384 case 's': 385 str = va_arg (args, char *); 386 (*callbacks->write_output) (str, strlen (str)); 387 break; 388 case 'd': 389 num = va_arg (args, int); 390 sprintf (buf, "%d", num); 391 (*callbacks->write_output) (buf, strlen (buf)); 392 break; 393 case 'c': 394 ch = va_arg (args, int); 395 buf[0] = ch; 396 (*callbacks->write_output) (buf, 1); 397 break; 398 default: 399 (*callbacks->write_output) (msg, sizeof (msg) - 1); 400 /* Don't just keep going, because q + 1 might point to the 401 terminating '\0'. */ 402 goto out; 403 } 404 p = q + 2; 405 } 406 (*callbacks->write_output) (p, strlen (p)); 407 } 408 else 409 vfprintf (outfile, format, args); 410 out: 411 va_end (args); 412 } 413 414 /* Flush the output file. */ 415 416 void 417 flush_output () 418 { 419 if (callbacks && callbacks->flush_output) 420 (*callbacks->flush_output) (); 421 else 422 fflush (outfile); 423 } 424 425 /* Compare two lines (typically one from each input file) 427 according to the command line options. 428 For efficiency, this is invoked only when the lines do not match exactly 429 but an option like -i might cause us to ignore the difference. 430 Return nonzero if the lines differ. */ 431 432 int 433 line_cmp (s1, s2) 434 char const *s1, *s2; 435 { 436 register unsigned char const *t1 = (unsigned char const *) s1; 437 register unsigned char const *t2 = (unsigned char const *) s2; 438 439 while (1) 440 { 441 register unsigned char c1 = *t1++; 442 register unsigned char c2 = *t2++; 443 444 /* Test for exact char equality first, since it's a common case. */ 445 if (c1 != c2) 446 { 447 /* Ignore horizontal white space if -b or -w is specified. */ 448 449 if (ignore_all_space_flag) 450 { 451 /* For -w, just skip past any white space. */ 452 while (ISSPACE (c1) && c1 != '\n') c1 = *t1++; 453 while (ISSPACE (c2) && c2 != '\n') c2 = *t2++; 454 } 455 else if (ignore_space_change_flag) 456 { 457 /* For -b, advance past any sequence of white space in line 1 458 and consider it just one Space, or nothing at all 459 if it is at the end of the line. */ 460 if (ISSPACE (c1)) 461 { 462 while (c1 != '\n') 463 { 464 c1 = *t1++; 465 if (! ISSPACE (c1)) 466 { 467 --t1; 468 c1 = ' '; 469 break; 470 } 471 } 472 } 473 474 /* Likewise for line 2. */ 475 if (ISSPACE (c2)) 476 { 477 while (c2 != '\n') 478 { 479 c2 = *t2++; 480 if (! ISSPACE (c2)) 481 { 482 --t2; 483 c2 = ' '; 484 break; 485 } 486 } 487 } 488 489 if (c1 != c2) 490 { 491 /* If we went too far when doing the simple test 492 for equality, go back to the first non-white-space 493 character in both sides and try again. */ 494 if (c2 == ' ' && c1 != '\n' 495 && (unsigned char const *) s1 + 1 < t1 496 && ISSPACE(t1[-2])) 497 { 498 --t1; 499 continue; 500 } 501 if (c1 == ' ' && c2 != '\n' 502 && (unsigned char const *) s2 + 1 < t2 503 && ISSPACE(t2[-2])) 504 { 505 --t2; 506 continue; 507 } 508 } 509 } 510 511 /* Lowercase all letters if -i is specified. */ 512 513 if (ignore_case_flag) 514 { 515 if (ISUPPER (c1)) 516 c1 = tolower (c1); 517 if (ISUPPER (c2)) 518 c2 = tolower (c2); 519 } 520 521 if (c1 != c2) 522 break; 523 } 524 if (c1 == '\n') 525 return 0; 526 } 527 528 return (1); 529 } 530 531 /* Find the consecutive changes at the start of the script START. 533 Return the last link before the first gap. */ 534 535 struct change * 536 find_change (start) 537 struct change *start; 538 { 539 return start; 540 } 541 542 struct change * 543 find_reverse_change (start) 544 struct change *start; 545 { 546 return start; 547 } 548 549 /* Divide SCRIPT into pieces by calling HUNKFUN and 551 print each piece with PRINTFUN. 552 Both functions take one arg, an edit script. 553 554 HUNKFUN is called with the tail of the script 555 and returns the last link that belongs together with the start 556 of the tail. 557 558 PRINTFUN takes a subscript which belongs together (with a null 559 link at the end) and prints it. */ 560 561 void 562 print_script (script, hunkfun, printfun) 563 struct change *script; 564 struct change * (*hunkfun) PARAMS((struct change *)); 565 void (*printfun) PARAMS((struct change *)); 566 { 567 struct change *next = script; 568 569 while (next) 570 { 571 struct change *this, *end; 572 573 /* Find a set of changes that belong together. */ 574 this = next; 575 end = (*hunkfun) (next); 576 577 /* Disconnect them from the rest of the changes, 578 making them a hunk, and remember the rest for next iteration. */ 579 next = end->link; 580 end->link = 0; 581 #ifdef DEBUG 582 debug_script (this); 583 #endif 584 585 /* Print this hunk. */ 586 (*printfun) (this); 587 588 /* Reconnect the script so it will all be freed properly. */ 589 end->link = next; 590 } 591 } 592 593 /* Print the text of a single line LINE, 595 flagging it with the characters in LINE_FLAG (which say whether 596 the line is inserted, deleted, changed, etc.). */ 597 598 void 599 print_1_line (line_flag, line) 600 char const *line_flag; 601 char const * const *line; 602 { 603 char const *text = line[0], *limit = line[1]; /* Help the compiler. */ 604 char const *flag_format = 0; 605 606 /* If -T was specified, use a Tab between the line-flag and the text. 607 Otherwise use a Space (as Unix diff does). 608 Print neither space nor tab if line-flags are empty. */ 609 610 if (line_flag && *line_flag) 611 { 612 flag_format = tab_align_flag ? "%s\t" : "%s "; 613 printf_output (flag_format, line_flag); 614 } 615 616 output_1_line (text, limit, flag_format, line_flag); 617 618 if ((!line_flag || line_flag[0]) && limit[-1] != '\n') 619 printf_output ("\n\\ No newline at end of file\n"); 620 } 621 622 /* Output a line from TEXT up to LIMIT. Without -t, output verbatim. 623 With -t, expand white space characters to spaces, and if FLAG_FORMAT 624 is nonzero, output it with argument LINE_FLAG after every 625 internal carriage return, so that tab stops continue to line up. */ 626 627 void 628 output_1_line (text, limit, flag_format, line_flag) 629 char const *text, *limit, *flag_format, *line_flag; 630 { 631 if (!tab_expand_flag) 632 write_output (text, limit - text); 633 else 634 { 635 register unsigned char c; 636 register char const *t = text; 637 register unsigned column = 0; 638 /* CC is used to avoid taking the address of the register 639 variable C. */ 640 char cc; 641 642 while (t < limit) 643 switch ((c = *t++)) 644 { 645 case '\t': 646 { 647 unsigned spaces = TAB_WIDTH - column % TAB_WIDTH; 648 column += spaces; 649 do 650 write_output (" ", 1); 651 while (--spaces); 652 } 653 break; 654 655 case '\r': 656 write_output ("\r", 1); 657 if (flag_format && t < limit && *t != '\n') 658 printf_output (flag_format, line_flag); 659 column = 0; 660 break; 661 662 case '\b': 663 if (column == 0) 664 continue; 665 column--; 666 write_output ("\b", 1); 667 break; 668 669 default: 670 if (ISPRINT (c)) 671 column++; 672 cc = c; 673 write_output (&cc, 1); 674 break; 675 } 676 } 677 } 678 679 int 680 change_letter (inserts, deletes) 681 int inserts, deletes; 682 { 683 if (!inserts) 684 return 'd'; 685 else if (!deletes) 686 return 'a'; 687 else 688 return 'c'; 689 } 690 691 /* Translate an internal line number (an index into diff's table of lines) 693 into an actual line number in the input file. 694 The internal line number is LNUM. FILE points to the data on the file. 695 696 Internal line numbers count from 0 starting after the prefix. 697 Actual line numbers count from 1 within the entire file. */ 698 699 int 700 translate_line_number (file, lnum) 701 struct file_data const *file; 702 int lnum; 703 { 704 return lnum + file->prefix_lines + 1; 705 } 706 707 void 708 translate_range (file, a, b, aptr, bptr) 709 struct file_data const *file; 710 int a, b; 711 int *aptr, *bptr; 712 { 713 *aptr = translate_line_number (file, a - 1) + 1; 714 *bptr = translate_line_number (file, b + 1) - 1; 715 } 716 717 /* Print a pair of line numbers with SEPCHAR, translated for file FILE. 718 If the two numbers are identical, print just one number. 719 720 Args A and B are internal line numbers. 721 We print the translated (real) line numbers. */ 722 723 void 724 print_number_range (sepchar, file, a, b) 725 int sepchar; 726 struct file_data *file; 727 int a, b; 728 { 729 int trans_a, trans_b; 730 translate_range (file, a, b, &trans_a, &trans_b); 731 732 /* Note: we can have B < A in the case of a range of no lines. 733 In this case, we should print the line number before the range, 734 which is B. */ 735 if (trans_b > trans_a) 736 printf_output ("%d%c%d", trans_a, sepchar, trans_b); 737 else 738 printf_output ("%d", trans_b); 739 } 740 741 /* Look at a hunk of edit script and report the range of lines in each file 743 that it applies to. HUNK is the start of the hunk, which is a chain 744 of `struct change'. The first and last line numbers of file 0 are stored in 745 *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. 746 Note that these are internal line numbers that count from 0. 747 748 If no lines from file 0 are deleted, then FIRST0 is LAST0+1. 749 750 Also set *DELETES nonzero if any lines of file 0 are deleted 751 and set *INSERTS nonzero if any lines of file 1 are inserted. 752 If only ignorable lines are inserted or deleted, both are 753 set to 0. */ 754 755 void 756 analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) 757 struct change *hunk; 758 int *first0, *last0, *first1, *last1; 759 int *deletes, *inserts; 760 { 761 int l0, l1, show_from, show_to; 762 int i; 763 int trivial = ignore_blank_lines_flag || ignore_regexp_list; 764 struct change *next; 765 766 show_from = show_to = 0; 767 768 *first0 = hunk->line0; 769 *first1 = hunk->line1; 770 771 next = hunk; 772 do 773 { 774 l0 = next->line0 + next->deleted - 1; 775 l1 = next->line1 + next->inserted - 1; 776 show_from += next->deleted; 777 show_to += next->inserted; 778 779 for (i = next->line0; i <= l0 && trivial; i++) 780 if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n') 781 { 782 struct regexp_list *r; 783 char const *line = files[0].linbuf[i]; 784 int len = files[0].linbuf[i + 1] - line; 785 786 for (r = ignore_regexp_list; r; r = r->next) 787 if (0 <= re_search (&r->buf, line, len, 0, len, 0)) 788 break; /* Found a match. Ignore this line. */ 789 /* If we got all the way through the regexp list without 790 finding a match, then it's nontrivial. */ 791 if (!r) 792 trivial = 0; 793 } 794 795 for (i = next->line1; i <= l1 && trivial; i++) 796 if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n') 797 { 798 struct regexp_list *r; 799 char const *line = files[1].linbuf[i]; 800 int len = files[1].linbuf[i + 1] - line; 801 802 for (r = ignore_regexp_list; r; r = r->next) 803 if (0 <= re_search (&r->buf, line, len, 0, len, 0)) 804 break; /* Found a match. Ignore this line. */ 805 /* If we got all the way through the regexp list without 806 finding a match, then it's nontrivial. */ 807 if (!r) 808 trivial = 0; 809 } 810 } 811 while ((next = next->link) != 0); 812 813 *last0 = l0; 814 *last1 = l1; 815 816 /* If all inserted or deleted lines are ignorable, 817 tell the caller to ignore this hunk. */ 818 819 if (trivial) 820 show_from = show_to = 0; 821 822 *deletes = show_from; 823 *inserts = show_to; 824 } 825 826 /* Concatenate three strings, returning a newly malloc'd string. */ 828 829 char * 830 concat (s1, s2, s3) 831 char const *s1, *s2, *s3; 832 { 833 size_t len = strlen (s1) + strlen (s2) + strlen (s3); 834 char *new = xmalloc (len + 1); 835 sprintf (new, "%s%s%s", s1, s2, s3); 836 return new; 837 } 838 839 /* Yield the newly malloc'd pathname 840 of the file in DIR whose filename is FILE. */ 841 842 char * 843 dir_file_pathname (dir, file) 844 char const *dir, *file; 845 { 846 char const *p = filename_lastdirchar (dir); 847 return concat (dir, "/" + (p && !p[1]), file); 848 } 849 850 void 852 debug_script (sp) 853 struct change *sp; 854 { 855 fflush (stdout); 856 for (; sp; sp = sp->link) 857 fprintf (stderr, "%3d %3d delete %d insert %d\n", 858 sp->line0, sp->line1, sp->deleted, sp->inserted); 859 fflush (stderr); 860 } 861