util.c revision 170755
155682Smarkm/* Support routines for GNU DIFF. 255682Smarkm 355682Smarkm Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002, 455682Smarkm 2004 Free Software Foundation, Inc. 555682Smarkm 655682Smarkm This file is part of GNU DIFF. 755682Smarkm 855682Smarkm GNU DIFF is free software; you can redistribute it and/or modify 955682Smarkm it under the terms of the GNU General Public License as published by 1055682Smarkm the Free Software Foundation; either version 2, or (at your option) 1155682Smarkm any later version. 1255682Smarkm 1355682Smarkm GNU DIFF is distributed in the hope that it will be useful, 1455682Smarkm but WITHOUT ANY WARRANTY; without even the implied warranty of 1555682Smarkm MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1655682Smarkm GNU General Public License for more details. 1755682Smarkm 1855682Smarkm You should have received a copy of the GNU General Public License 1955682Smarkm along with this program; see the file COPYING. 2055682Smarkm If not, write to the Free Software Foundation, 2155682Smarkm 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2255682Smarkm 2355682Smarkm#include "diff.h" 2455682Smarkm#include <dirname.h> 2555682Smarkm#include <error.h> 2655682Smarkm#include <quotesys.h> 2755682Smarkm#include <xalloc.h> 2855682Smarkm 2955682Smarkmchar const pr_program[] = PR_PROGRAM; 3055682Smarkm 3155682Smarkm/* Queue up one-line messages to be printed at the end, 3255682Smarkm when -l is specified. Each message is recorded with a `struct msg'. */ 3355682Smarkm 3455682Smarkmstruct msg 3555682Smarkm{ 3655682Smarkm struct msg *next; 3755682Smarkm char args[1]; /* Format + 4 args, each '\0' terminated, concatenated. */ 3855682Smarkm}; 3955682Smarkm 4055682Smarkm/* Head of the chain of queues messages. */ 4155682Smarkm 4255682Smarkmstatic struct msg *msg_chain; 4355682Smarkm 4455682Smarkm/* Tail of the chain of queues messages. */ 4555682Smarkm 4655682Smarkmstatic struct msg **msg_chain_end = &msg_chain; 4755682Smarkm 4855682Smarkm/* Use when a system call returns non-zero status. 4955682Smarkm NAME should normally be the file name. */ 5055682Smarkm 5155682Smarkmvoid 5255682Smarkmperror_with_name (char const *name) 5355682Smarkm{ 5455682Smarkm error (0, errno, "%s", name); 5555682Smarkm} 5655682Smarkm 5755682Smarkm/* Use when a system call returns non-zero status and that is fatal. */ 5855682Smarkm 5955682Smarkmvoid 6055682Smarkmpfatal_with_name (char const *name) 6155682Smarkm{ 6255682Smarkm int e = errno; 6355682Smarkm print_message_queue (); 6455682Smarkm error (EXIT_TROUBLE, e, "%s", name); 6555682Smarkm abort (); 6655682Smarkm} 6755682Smarkm 6855682Smarkm/* Print an error message containing MSGID, then exit. */ 6955682Smarkm 7055682Smarkmvoid 7155682Smarkmfatal (char const *msgid) 7255682Smarkm{ 7355682Smarkm print_message_queue (); 7455682Smarkm error (EXIT_TROUBLE, 0, "%s", _(msgid)); 7555682Smarkm abort (); 7655682Smarkm} 7755682Smarkm 7855682Smarkm/* Like printf, except if -l in effect then save the message and print later. 7955682Smarkm This is used for things like "Only in ...". */ 8055682Smarkm 8155682Smarkmvoid 8255682Smarkmmessage (char const *format_msgid, char const *arg1, char const *arg2) 8355682Smarkm{ 8455682Smarkm message5 (format_msgid, arg1, arg2, 0, 0); 8555682Smarkm} 8655682Smarkm 8755682Smarkmvoid 8855682Smarkmmessage5 (char const *format_msgid, char const *arg1, char const *arg2, 8955682Smarkm char const *arg3, char const *arg4) 9055682Smarkm{ 9155682Smarkm if (paginate) 9255682Smarkm { 9355682Smarkm char *p; 9455682Smarkm char const *arg[5]; 9555682Smarkm int i; 9655682Smarkm size_t size[5]; 9755682Smarkm size_t total_size = offsetof (struct msg, args); 9855682Smarkm struct msg *new; 9955682Smarkm 10055682Smarkm arg[0] = format_msgid; 10155682Smarkm arg[1] = arg1; 10255682Smarkm arg[2] = arg2; 10355682Smarkm arg[3] = arg3 ? arg3 : ""; 10455682Smarkm arg[4] = arg4 ? arg4 : ""; 10555682Smarkm 10655682Smarkm for (i = 0; i < 5; i++) 10755682Smarkm total_size += size[i] = strlen (arg[i]) + 1; 10855682Smarkm 10955682Smarkm new = xmalloc (total_size); 11055682Smarkm 11155682Smarkm for (i = 0, p = new->args; i < 5; p += size[i++]) 11255682Smarkm memcpy (p, arg[i], size[i]); 11355682Smarkm 11455682Smarkm *msg_chain_end = new; 11555682Smarkm new->next = 0; 11655682Smarkm msg_chain_end = &new->next; 11755682Smarkm } 11855682Smarkm else 11955682Smarkm { 12055682Smarkm if (sdiff_merge_assist) 12155682Smarkm putchar (' '); 12255682Smarkm printf (_(format_msgid), arg1, arg2, arg3, arg4); 12355682Smarkm } 12455682Smarkm} 12555682Smarkm 12655682Smarkm/* Output all the messages that were saved up by calls to `message'. */ 12755682Smarkm 12855682Smarkmvoid 12955682Smarkmprint_message_queue (void) 13055682Smarkm{ 13155682Smarkm char const *arg[5]; 13255682Smarkm int i; 13355682Smarkm struct msg *m = msg_chain; 13455682Smarkm 13555682Smarkm while (m) 13655682Smarkm { 13755682Smarkm struct msg *next = m->next; 13855682Smarkm arg[0] = m->args; 13955682Smarkm for (i = 0; i < 4; i++) 14055682Smarkm arg[i + 1] = arg[i] + strlen (arg[i]) + 1; 14155682Smarkm printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]); 14255682Smarkm free (m); 14355682Smarkm m = next; 14455682Smarkm } 14555682Smarkm} 14655682Smarkm 14755682Smarkm/* Call before outputting the results of comparing files NAME0 and NAME1 14855682Smarkm to set up OUTFILE, the stdio stream for the output to go to. 14955682Smarkm 15055682Smarkm Usually, OUTFILE is just stdout. But when -l was specified 15155682Smarkm we fork off a `pr' and make OUTFILE a pipe to it. 15255682Smarkm `pr' then outputs to our stdout. */ 15355682Smarkm 15455682Smarkmstatic char const *current_name0; 15555682Smarkmstatic char const *current_name1; 15655682Smarkmstatic bool currently_recursive; 15755682Smarkm 15855682Smarkmvoid 15955682Smarkmsetup_output (char const *name0, char const *name1, bool recursive) 16055682Smarkm{ 16155682Smarkm current_name0 = name0; 16255682Smarkm current_name1 = name1; 16355682Smarkm currently_recursive = recursive; 16455682Smarkm outfile = 0; 16555682Smarkm} 16655682Smarkm 16755682Smarkm#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK 16855682Smarkmstatic pid_t pr_pid; 16955682Smarkm#endif 17055682Smarkm 17155682Smarkmvoid 17255682Smarkmbegin_output (void) 17355682Smarkm{ 17455682Smarkm char *name; 17555682Smarkm 17655682Smarkm if (outfile != 0) 17755682Smarkm return; 17855682Smarkm 17955682Smarkm /* Construct the header of this piece of diff. */ 18055682Smarkm name = xmalloc (strlen (current_name0) + strlen (current_name1) 18155682Smarkm + strlen (switch_string) + 7); 18255682Smarkm 18355682Smarkm /* POSIX 1003.1-2001 specifies this format. But there are some bugs in 18455682Smarkm the standard: it says that we must print only the last component 18555682Smarkm of the pathnames, and it requires two spaces after "diff" if 18655682Smarkm there are no options. These requirements are silly and do not 18755682Smarkm match historical practice. */ 18855682Smarkm sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1); 18955682Smarkm 19055682Smarkm if (paginate) 19155682Smarkm { 19255682Smarkm if (fflush (stdout) != 0) 19355682Smarkm pfatal_with_name (_("write failed")); 19455682Smarkm 19555682Smarkm /* Make OUTFILE a pipe to a subsidiary `pr'. */ 19655682Smarkm { 19755682Smarkm#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK 19855682Smarkm int pipes[2]; 19955682Smarkm 20055682Smarkm if (pipe (pipes) != 0) 20155682Smarkm pfatal_with_name ("pipe"); 20255682Smarkm 20355682Smarkm pr_pid = vfork (); 20455682Smarkm if (pr_pid < 0) 20555682Smarkm pfatal_with_name ("fork"); 20655682Smarkm 20755682Smarkm if (pr_pid == 0) 20855682Smarkm { 20955682Smarkm close (pipes[1]); 21055682Smarkm if (pipes[0] != STDIN_FILENO) 21155682Smarkm { 21255682Smarkm if (dup2 (pipes[0], STDIN_FILENO) < 0) 21355682Smarkm pfatal_with_name ("dup2"); 21455682Smarkm close (pipes[0]); 21555682Smarkm } 21655682Smarkm 21755682Smarkm execl (pr_program, pr_program, "-h", name, (char *) 0); 21855682Smarkm _exit (errno == ENOENT ? 127 : 126); 21955682Smarkm } 22055682Smarkm else 22155682Smarkm { 22255682Smarkm close (pipes[0]); 22355682Smarkm outfile = fdopen (pipes[1], "w"); 22455682Smarkm if (!outfile) 22555682Smarkm pfatal_with_name ("fdopen"); 22655682Smarkm } 22755682Smarkm#else 22855682Smarkm char *command = xmalloc (sizeof pr_program - 1 + 7 22955682Smarkm + quote_system_arg ((char *) 0, name) + 1); 23055682Smarkm char *p; 23155682Smarkm sprintf (command, "%s -f -h ", pr_program); 23255682Smarkm p = command + sizeof pr_program - 1 + 7; 23355682Smarkm p += quote_system_arg (p, name); 23455682Smarkm *p = 0; 23555682Smarkm errno = 0; 23655682Smarkm outfile = popen (command, "w"); 23755682Smarkm if (!outfile) 23855682Smarkm pfatal_with_name (command); 23955682Smarkm free (command); 24055682Smarkm#endif 24155682Smarkm } 24255682Smarkm } 24355682Smarkm else 24455682Smarkm { 24555682Smarkm 24655682Smarkm /* If -l was not specified, output the diff straight to `stdout'. */ 24755682Smarkm 24855682Smarkm outfile = stdout; 24955682Smarkm 25055682Smarkm /* If handling multiple files (because scanning a directory), 25155682Smarkm print which files the following output is about. */ 25255682Smarkm if (currently_recursive) 25355682Smarkm printf ("%s\n", name); 25455682Smarkm } 25555682Smarkm 25655682Smarkm free (name); 25755682Smarkm 25855682Smarkm /* A special header is needed at the beginning of context output. */ 25955682Smarkm switch (output_style) 26055682Smarkm { 26155682Smarkm case OUTPUT_CONTEXT: 26255682Smarkm print_context_header (files, false); 26355682Smarkm break; 26455682Smarkm 26555682Smarkm case OUTPUT_UNIFIED: 26655682Smarkm print_context_header (files, true); 26755682Smarkm break; 26855682Smarkm 26955682Smarkm default: 27055682Smarkm break; 27155682Smarkm } 27255682Smarkm} 27355682Smarkm 27455682Smarkm/* Call after the end of output of diffs for one file. 27555682Smarkm Close OUTFILE and get rid of the `pr' subfork. */ 27655682Smarkm 27755682Smarkmvoid 27855682Smarkmfinish_output (void) 27955682Smarkm{ 28055682Smarkm if (outfile != 0 && outfile != stdout) 28155682Smarkm { 28255682Smarkm int status; 28355682Smarkm int wstatus; 28455682Smarkm int werrno = 0; 28555682Smarkm if (ferror (outfile)) 28655682Smarkm fatal ("write failed"); 28755682Smarkm#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK) 28855682Smarkm wstatus = pclose (outfile); 28955682Smarkm if (wstatus == -1) 29055682Smarkm werrno = errno; 29155682Smarkm#else 29255682Smarkm if (fclose (outfile) != 0) 29355682Smarkm pfatal_with_name (_("write failed")); 29455682Smarkm if (waitpid (pr_pid, &wstatus, 0) < 0) 29555682Smarkm pfatal_with_name ("waitpid"); 29655682Smarkm#endif 29755682Smarkm status = (! werrno && WIFEXITED (wstatus) 29855682Smarkm ? WEXITSTATUS (wstatus) 29955682Smarkm : INT_MAX); 30055682Smarkm if (status) 30155682Smarkm error (EXIT_TROUBLE, werrno, 30255682Smarkm _(status == 126 30355682Smarkm ? "subsidiary program `%s' could not be invoked" 30455682Smarkm : status == 127 30555682Smarkm ? "subsidiary program `%s' not found" 30655682Smarkm : status == INT_MAX 30755682Smarkm ? "subsidiary program `%s' failed" 30855682Smarkm : "subsidiary program `%s' failed (exit status %d)"), 30955682Smarkm pr_program, status); 31055682Smarkm } 31155682Smarkm 31255682Smarkm outfile = 0; 31355682Smarkm} 31455682Smarkm 31555682Smarkm/* Compare two lines (typically one from each input file) 31655682Smarkm according to the command line options. 31755682Smarkm For efficiency, this is invoked only when the lines do not match exactly 31855682Smarkm but an option like -i might cause us to ignore the difference. 31955682Smarkm Return nonzero if the lines differ. */ 32055682Smarkm 32155682Smarkmbool 32255682Smarkmlines_differ (char const *s1, char const *s2) 32355682Smarkm{ 32455682Smarkm register char const *t1 = s1; 32555682Smarkm register char const *t2 = s2; 32655682Smarkm size_t column = 0; 32755682Smarkm 32855682Smarkm while (1) 32955682Smarkm { 33055682Smarkm register unsigned char c1 = *t1++; 33155682Smarkm register unsigned char c2 = *t2++; 33255682Smarkm 33355682Smarkm /* Test for exact char equality first, since it's a common case. */ 33455682Smarkm if (c1 != c2) 335 { 336 switch (ignore_white_space) 337 { 338 case IGNORE_ALL_SPACE: 339 /* For -w, just skip past any white space. */ 340 while (isspace (c1) && c1 != '\n') c1 = *t1++; 341 while (isspace (c2) && c2 != '\n') c2 = *t2++; 342 break; 343 344 case IGNORE_SPACE_CHANGE: 345 /* For -b, advance past any sequence of white space in 346 line 1 and consider it just one space, or nothing at 347 all if it is at the end of the line. */ 348 if (isspace (c1)) 349 { 350 while (c1 != '\n') 351 { 352 c1 = *t1++; 353 if (! isspace (c1)) 354 { 355 --t1; 356 c1 = ' '; 357 break; 358 } 359 } 360 } 361 362 /* Likewise for line 2. */ 363 if (isspace (c2)) 364 { 365 while (c2 != '\n') 366 { 367 c2 = *t2++; 368 if (! isspace (c2)) 369 { 370 --t2; 371 c2 = ' '; 372 break; 373 } 374 } 375 } 376 377 if (c1 != c2) 378 { 379 /* If we went too far when doing the simple test 380 for equality, go back to the first non-white-space 381 character in both sides and try again. */ 382 if (c2 == ' ' && c1 != '\n' 383 && s1 + 1 < t1 384 && isspace ((unsigned char) t1[-2])) 385 { 386 --t1; 387 continue; 388 } 389 if (c1 == ' ' && c2 != '\n' 390 && s2 + 1 < t2 391 && isspace ((unsigned char) t2[-2])) 392 { 393 --t2; 394 continue; 395 } 396 } 397 398 break; 399 400 case IGNORE_TAB_EXPANSION: 401 if ((c1 == ' ' && c2 == '\t') 402 || (c1 == '\t' && c2 == ' ')) 403 { 404 size_t column2 = column; 405 for (;; c1 = *t1++) 406 { 407 if (c1 == ' ') 408 column++; 409 else if (c1 == '\t') 410 column += tabsize - column % tabsize; 411 else 412 break; 413 } 414 for (;; c2 = *t2++) 415 { 416 if (c2 == ' ') 417 column2++; 418 else if (c2 == '\t') 419 column2 += tabsize - column2 % tabsize; 420 else 421 break; 422 } 423 if (column != column2) 424 return true; 425 } 426 break; 427 428 case IGNORE_NO_WHITE_SPACE: 429 break; 430 } 431 432 /* Lowercase all letters if -i is specified. */ 433 434 if (ignore_case) 435 { 436 c1 = tolower (c1); 437 c2 = tolower (c2); 438 } 439 440 if (c1 != c2) 441 break; 442 } 443 if (c1 == '\n') 444 return false; 445 446 column += c1 == '\t' ? tabsize - column % tabsize : 1; 447 } 448 449 return true; 450} 451 452/* Find the consecutive changes at the start of the script START. 453 Return the last link before the first gap. */ 454 455struct change * 456find_change (struct change *start) 457{ 458 return start; 459} 460 461struct change * 462find_reverse_change (struct change *start) 463{ 464 return start; 465} 466 467/* Divide SCRIPT into pieces by calling HUNKFUN and 468 print each piece with PRINTFUN. 469 Both functions take one arg, an edit script. 470 471 HUNKFUN is called with the tail of the script 472 and returns the last link that belongs together with the start 473 of the tail. 474 475 PRINTFUN takes a subscript which belongs together (with a null 476 link at the end) and prints it. */ 477 478void 479print_script (struct change *script, 480 struct change * (*hunkfun) (struct change *), 481 void (*printfun) (struct change *)) 482{ 483 struct change *next = script; 484 485 while (next) 486 { 487 struct change *this, *end; 488 489 /* Find a set of changes that belong together. */ 490 this = next; 491 end = (*hunkfun) (next); 492 493 /* Disconnect them from the rest of the changes, 494 making them a hunk, and remember the rest for next iteration. */ 495 next = end->link; 496 end->link = 0; 497#ifdef DEBUG 498 debug_script (this); 499#endif 500 501 /* Print this hunk. */ 502 (*printfun) (this); 503 504 /* Reconnect the script so it will all be freed properly. */ 505 end->link = next; 506 } 507} 508 509/* Print the text of a single line LINE, 510 flagging it with the characters in LINE_FLAG (which say whether 511 the line is inserted, deleted, changed, etc.). */ 512 513void 514print_1_line (char const *line_flag, char const *const *line) 515{ 516 char const *base = line[0], *limit = line[1]; /* Help the compiler. */ 517 FILE *out = outfile; /* Help the compiler some more. */ 518 char const *flag_format = 0; 519 520 /* If -T was specified, use a Tab between the line-flag and the text. 521 Otherwise use a Space (as Unix diff does). 522 Print neither space nor tab if line-flags are empty. */ 523 524 if (line_flag && *line_flag) 525 { 526 flag_format = initial_tab ? "%s\t" : "%s "; 527 fprintf (out, flag_format, line_flag); 528 } 529 530 output_1_line (base, limit, flag_format, line_flag); 531 532 if ((!line_flag || line_flag[0]) && limit[-1] != '\n') 533 fprintf (out, "\n\\ %s\n", _("No newline at end of file")); 534} 535 536/* Output a line from BASE up to LIMIT. 537 With -t, expand white space characters to spaces, and if FLAG_FORMAT 538 is nonzero, output it with argument LINE_FLAG after every 539 internal carriage return, so that tab stops continue to line up. */ 540 541void 542output_1_line (char const *base, char const *limit, char const *flag_format, 543 char const *line_flag) 544{ 545 if (!expand_tabs) 546 fwrite (base, sizeof (char), limit - base, outfile); 547 else 548 { 549 register FILE *out = outfile; 550 register unsigned char c; 551 register char const *t = base; 552 register size_t column = 0; 553 size_t tab_size = tabsize; 554 555 while (t < limit) 556 switch ((c = *t++)) 557 { 558 case '\t': 559 { 560 size_t spaces = tab_size - column % tab_size; 561 column += spaces; 562 do 563 putc (' ', out); 564 while (--spaces); 565 } 566 break; 567 568 case '\r': 569 putc (c, out); 570 if (flag_format && t < limit && *t != '\n') 571 fprintf (out, flag_format, line_flag); 572 column = 0; 573 break; 574 575 case '\b': 576 if (column == 0) 577 continue; 578 column--; 579 putc (c, out); 580 break; 581 582 default: 583 column += isprint (c) != 0; 584 putc (c, out); 585 break; 586 } 587 } 588} 589 590char const change_letter[] = { 0, 'd', 'a', 'c' }; 591 592/* Translate an internal line number (an index into diff's table of lines) 593 into an actual line number in the input file. 594 The internal line number is I. FILE points to the data on the file. 595 596 Internal line numbers count from 0 starting after the prefix. 597 Actual line numbers count from 1 within the entire file. */ 598 599lin 600translate_line_number (struct file_data const *file, lin i) 601{ 602 return i + file->prefix_lines + 1; 603} 604 605/* Translate a line number range. This is always done for printing, 606 so for convenience translate to long int rather than lin, so that the 607 caller can use printf with "%ld" without casting. */ 608 609void 610translate_range (struct file_data const *file, 611 lin a, lin b, 612 long int *aptr, long int *bptr) 613{ 614 *aptr = translate_line_number (file, a - 1) + 1; 615 *bptr = translate_line_number (file, b + 1) - 1; 616} 617 618/* Print a pair of line numbers with SEPCHAR, translated for file FILE. 619 If the two numbers are identical, print just one number. 620 621 Args A and B are internal line numbers. 622 We print the translated (real) line numbers. */ 623 624void 625print_number_range (char sepchar, struct file_data *file, lin a, lin b) 626{ 627 long int trans_a, trans_b; 628 translate_range (file, a, b, &trans_a, &trans_b); 629 630 /* Note: we can have B < A in the case of a range of no lines. 631 In this case, we should print the line number before the range, 632 which is B. */ 633 if (trans_b > trans_a) 634 fprintf (outfile, "%ld%c%ld", trans_a, sepchar, trans_b); 635 else 636 fprintf (outfile, "%ld", trans_b); 637} 638 639/* Look at a hunk of edit script and report the range of lines in each file 640 that it applies to. HUNK is the start of the hunk, which is a chain 641 of `struct change'. The first and last line numbers of file 0 are stored in 642 *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1. 643 Note that these are internal line numbers that count from 0. 644 645 If no lines from file 0 are deleted, then FIRST0 is LAST0+1. 646 647 Return UNCHANGED if only ignorable lines are inserted or deleted, 648 OLD if lines of file 0 are deleted, 649 NEW if lines of file 1 are inserted, 650 and CHANGED if both kinds of changes are found. */ 651 652enum changes 653analyze_hunk (struct change *hunk, 654 lin *first0, lin *last0, 655 lin *first1, lin *last1) 656{ 657 struct change *next; 658 lin l0, l1; 659 lin show_from, show_to; 660 lin i; 661 bool trivial = ignore_blank_lines || ignore_regexp.fastmap; 662 size_t trivial_length = ignore_blank_lines - 1; 663 /* If 0, ignore zero-length lines; 664 if SIZE_MAX, do not ignore lines just because of their length. */ 665 bool skip_leading_white_space = 666 (ignore_blank_lines && IGNORE_SPACE_CHANGE <= ignore_white_space); 667 668 char const * const *linbuf0 = files[0].linbuf; /* Help the compiler. */ 669 char const * const *linbuf1 = files[1].linbuf; 670 671 show_from = show_to = 0; 672 673 *first0 = hunk->line0; 674 *first1 = hunk->line1; 675 676 next = hunk; 677 do 678 { 679 l0 = next->line0 + next->deleted - 1; 680 l1 = next->line1 + next->inserted - 1; 681 show_from += next->deleted; 682 show_to += next->inserted; 683 684 for (i = next->line0; i <= l0 && trivial; i++) 685 { 686 char const *line = linbuf0[i]; 687 char const *newline = linbuf0[i + 1] - 1; 688 size_t len = newline - line; 689 char const *p = line; 690 if (skip_leading_white_space) 691 while (isspace ((unsigned char) *p) && *p != '\n') 692 p++; 693 if (newline - p != trivial_length 694 && (! ignore_regexp.fastmap 695 || re_search (&ignore_regexp, line, len, 0, len, 0) < 0)) 696 trivial = 0; 697 } 698 699 for (i = next->line1; i <= l1 && trivial; i++) 700 { 701 char const *line = linbuf1[i]; 702 char const *newline = linbuf1[i + 1] - 1; 703 size_t len = newline - line; 704 char const *p = line; 705 if (skip_leading_white_space) 706 while (isspace ((unsigned char) *p) && *p != '\n') 707 p++; 708 if (newline - p != trivial_length 709 && (! ignore_regexp.fastmap 710 || re_search (&ignore_regexp, line, len, 0, len, 0) < 0)) 711 trivial = 0; 712 } 713 } 714 while ((next = next->link) != 0); 715 716 *last0 = l0; 717 *last1 = l1; 718 719 /* If all inserted or deleted lines are ignorable, 720 tell the caller to ignore this hunk. */ 721 722 if (trivial) 723 return UNCHANGED; 724 725 return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED); 726} 727 728/* Concatenate three strings, returning a newly malloc'd string. */ 729 730char * 731concat (char const *s1, char const *s2, char const *s3) 732{ 733 char *new = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1); 734 sprintf (new, "%s%s%s", s1, s2, s3); 735 return new; 736} 737 738/* Yield a new block of SIZE bytes, initialized to zero. */ 739 740void * 741zalloc (size_t size) 742{ 743 void *p = xmalloc (size); 744 memset (p, 0, size); 745 return p; 746} 747 748/* Yield the newly malloc'd pathname 749 of the file in DIR whose filename is FILE. */ 750 751char * 752dir_file_pathname (char const *dir, char const *file) 753{ 754 char const *base = base_name (dir); 755 bool omit_slash = !*base || base[strlen (base) - 1] == '/'; 756 return concat (dir, "/" + omit_slash, file); 757} 758 759void 760debug_script (struct change *sp) 761{ 762 fflush (stdout); 763 764 for (; sp; sp = sp->link) 765 { 766 long int line0 = sp->line0; 767 long int line1 = sp->line1; 768 long int deleted = sp->deleted; 769 long int inserted = sp->inserted; 770 fprintf (stderr, "%3ld %3ld delete %ld insert %ld\n", 771 line0, line1, deleted, inserted); 772 } 773 774 fflush (stderr); 775} 776