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