xref: /freebsd/contrib/diff/src/util.c (revision 18fd37a72c3a7549d2d4f6c6ea00bdcd2bdaca01)
118fd37a7SXin LI /* Support routines for GNU DIFF.
218fd37a7SXin LI 
318fd37a7SXin LI    Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002,
418fd37a7SXin LI    2004 Free Software Foundation, Inc.
518fd37a7SXin LI 
618fd37a7SXin LI    This file is part of GNU DIFF.
718fd37a7SXin LI 
818fd37a7SXin LI    GNU DIFF is free software; you can redistribute it and/or modify
918fd37a7SXin LI    it under the terms of the GNU General Public License as published by
1018fd37a7SXin LI    the Free Software Foundation; either version 2, or (at your option)
1118fd37a7SXin LI    any later version.
1218fd37a7SXin LI 
1318fd37a7SXin LI    GNU DIFF is distributed in the hope that it will be useful,
1418fd37a7SXin LI    but WITHOUT ANY WARRANTY; without even the implied warranty of
1518fd37a7SXin LI    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1618fd37a7SXin LI    GNU General Public License for more details.
1718fd37a7SXin LI 
1818fd37a7SXin LI    You should have received a copy of the GNU General Public License
1918fd37a7SXin LI    along with this program; see the file COPYING.
2018fd37a7SXin LI    If not, write to the Free Software Foundation,
2118fd37a7SXin LI    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2218fd37a7SXin LI 
2318fd37a7SXin LI #include "diff.h"
2418fd37a7SXin LI #include <dirname.h>
2518fd37a7SXin LI #include <error.h>
2618fd37a7SXin LI #include <quotesys.h>
2718fd37a7SXin LI #include <xalloc.h>
2818fd37a7SXin LI 
2918fd37a7SXin LI char const pr_program[] = PR_PROGRAM;
3018fd37a7SXin LI 
3118fd37a7SXin LI /* Queue up one-line messages to be printed at the end,
3218fd37a7SXin LI    when -l is specified.  Each message is recorded with a `struct msg'.  */
3318fd37a7SXin LI 
3418fd37a7SXin LI struct msg
3518fd37a7SXin LI {
3618fd37a7SXin LI   struct msg *next;
3718fd37a7SXin LI   char args[1]; /* Format + 4 args, each '\0' terminated, concatenated.  */
3818fd37a7SXin LI };
3918fd37a7SXin LI 
4018fd37a7SXin LI /* Head of the chain of queues messages.  */
4118fd37a7SXin LI 
4218fd37a7SXin LI static struct msg *msg_chain;
4318fd37a7SXin LI 
4418fd37a7SXin LI /* Tail of the chain of queues messages.  */
4518fd37a7SXin LI 
4618fd37a7SXin LI static struct msg **msg_chain_end = &msg_chain;
4718fd37a7SXin LI 
4818fd37a7SXin LI /* Use when a system call returns non-zero status.
4918fd37a7SXin LI    NAME should normally be the file name.  */
5018fd37a7SXin LI 
5118fd37a7SXin LI void
perror_with_name(char const * name)5218fd37a7SXin LI perror_with_name (char const *name)
5318fd37a7SXin LI {
5418fd37a7SXin LI   error (0, errno, "%s", name);
5518fd37a7SXin LI }
5618fd37a7SXin LI 
5718fd37a7SXin LI /* Use when a system call returns non-zero status and that is fatal.  */
5818fd37a7SXin LI 
5918fd37a7SXin LI void
pfatal_with_name(char const * name)6018fd37a7SXin LI pfatal_with_name (char const *name)
6118fd37a7SXin LI {
6218fd37a7SXin LI   int e = errno;
6318fd37a7SXin LI   print_message_queue ();
6418fd37a7SXin LI   error (EXIT_TROUBLE, e, "%s", name);
6518fd37a7SXin LI   abort ();
6618fd37a7SXin LI }
6718fd37a7SXin LI 
6818fd37a7SXin LI /* Print an error message containing MSGID, then exit.  */
6918fd37a7SXin LI 
7018fd37a7SXin LI void
fatal(char const * msgid)7118fd37a7SXin LI fatal (char const *msgid)
7218fd37a7SXin LI {
7318fd37a7SXin LI   print_message_queue ();
7418fd37a7SXin LI   error (EXIT_TROUBLE, 0, "%s", _(msgid));
7518fd37a7SXin LI   abort ();
7618fd37a7SXin LI }
7718fd37a7SXin LI 
7818fd37a7SXin LI /* Like printf, except if -l in effect then save the message and print later.
7918fd37a7SXin LI    This is used for things like "Only in ...".  */
8018fd37a7SXin LI 
8118fd37a7SXin LI void
message(char const * format_msgid,char const * arg1,char const * arg2)8218fd37a7SXin LI message (char const *format_msgid, char const *arg1, char const *arg2)
8318fd37a7SXin LI {
8418fd37a7SXin LI   message5 (format_msgid, arg1, arg2, 0, 0);
8518fd37a7SXin LI }
8618fd37a7SXin LI 
8718fd37a7SXin LI void
message5(char const * format_msgid,char const * arg1,char const * arg2,char const * arg3,char const * arg4)8818fd37a7SXin LI message5 (char const *format_msgid, char const *arg1, char const *arg2,
8918fd37a7SXin LI 	  char const *arg3, char const *arg4)
9018fd37a7SXin LI {
9118fd37a7SXin LI   if (paginate)
9218fd37a7SXin LI     {
9318fd37a7SXin LI       char *p;
9418fd37a7SXin LI       char const *arg[5];
9518fd37a7SXin LI       int i;
9618fd37a7SXin LI       size_t size[5];
9718fd37a7SXin LI       size_t total_size = offsetof (struct msg, args);
9818fd37a7SXin LI       struct msg *new;
9918fd37a7SXin LI 
10018fd37a7SXin LI       arg[0] = format_msgid;
10118fd37a7SXin LI       arg[1] = arg1;
10218fd37a7SXin LI       arg[2] = arg2;
10318fd37a7SXin LI       arg[3] = arg3 ? arg3 : "";
10418fd37a7SXin LI       arg[4] = arg4 ? arg4 : "";
10518fd37a7SXin LI 
10618fd37a7SXin LI       for (i = 0;  i < 5;  i++)
10718fd37a7SXin LI 	total_size += size[i] = strlen (arg[i]) + 1;
10818fd37a7SXin LI 
10918fd37a7SXin LI       new = xmalloc (total_size);
11018fd37a7SXin LI 
11118fd37a7SXin LI       for (i = 0, p = new->args;  i < 5;  p += size[i++])
11218fd37a7SXin LI 	memcpy (p, arg[i], size[i]);
11318fd37a7SXin LI 
11418fd37a7SXin LI       *msg_chain_end = new;
11518fd37a7SXin LI       new->next = 0;
11618fd37a7SXin LI       msg_chain_end = &new->next;
11718fd37a7SXin LI     }
11818fd37a7SXin LI   else
11918fd37a7SXin LI     {
12018fd37a7SXin LI       if (sdiff_merge_assist)
12118fd37a7SXin LI 	putchar (' ');
12218fd37a7SXin LI       printf (_(format_msgid), arg1, arg2, arg3, arg4);
12318fd37a7SXin LI     }
12418fd37a7SXin LI }
12518fd37a7SXin LI 
12618fd37a7SXin LI /* Output all the messages that were saved up by calls to `message'.  */
12718fd37a7SXin LI 
12818fd37a7SXin LI void
print_message_queue(void)12918fd37a7SXin LI print_message_queue (void)
13018fd37a7SXin LI {
13118fd37a7SXin LI   char const *arg[5];
13218fd37a7SXin LI   int i;
13318fd37a7SXin LI   struct msg *m = msg_chain;
13418fd37a7SXin LI 
13518fd37a7SXin LI   while (m)
13618fd37a7SXin LI     {
13718fd37a7SXin LI       struct msg *next = m->next;
13818fd37a7SXin LI       arg[0] = m->args;
13918fd37a7SXin LI       for (i = 0;  i < 4;  i++)
14018fd37a7SXin LI 	arg[i + 1] = arg[i] + strlen (arg[i]) + 1;
14118fd37a7SXin LI       printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]);
14218fd37a7SXin LI       free (m);
14318fd37a7SXin LI       m = next;
14418fd37a7SXin LI     }
14518fd37a7SXin LI }
14618fd37a7SXin LI 
14718fd37a7SXin LI /* Call before outputting the results of comparing files NAME0 and NAME1
14818fd37a7SXin LI    to set up OUTFILE, the stdio stream for the output to go to.
14918fd37a7SXin LI 
15018fd37a7SXin LI    Usually, OUTFILE is just stdout.  But when -l was specified
15118fd37a7SXin LI    we fork off a `pr' and make OUTFILE a pipe to it.
15218fd37a7SXin LI    `pr' then outputs to our stdout.  */
15318fd37a7SXin LI 
15418fd37a7SXin LI static char const *current_name0;
15518fd37a7SXin LI static char const *current_name1;
15618fd37a7SXin LI static bool currently_recursive;
15718fd37a7SXin LI 
15818fd37a7SXin LI void
setup_output(char const * name0,char const * name1,bool recursive)15918fd37a7SXin LI setup_output (char const *name0, char const *name1, bool recursive)
16018fd37a7SXin LI {
16118fd37a7SXin LI   current_name0 = name0;
16218fd37a7SXin LI   current_name1 = name1;
16318fd37a7SXin LI   currently_recursive = recursive;
16418fd37a7SXin LI   outfile = 0;
16518fd37a7SXin LI }
16618fd37a7SXin LI 
16718fd37a7SXin LI #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
16818fd37a7SXin LI static pid_t pr_pid;
16918fd37a7SXin LI #endif
17018fd37a7SXin LI 
17118fd37a7SXin LI void
begin_output(void)17218fd37a7SXin LI begin_output (void)
17318fd37a7SXin LI {
17418fd37a7SXin LI   char *name;
17518fd37a7SXin LI 
17618fd37a7SXin LI   if (outfile != 0)
17718fd37a7SXin LI     return;
17818fd37a7SXin LI 
17918fd37a7SXin LI   /* Construct the header of this piece of diff.  */
18018fd37a7SXin LI   name = xmalloc (strlen (current_name0) + strlen (current_name1)
18118fd37a7SXin LI 		  + strlen (switch_string) + 7);
18218fd37a7SXin LI 
18318fd37a7SXin LI   /* POSIX 1003.1-2001 specifies this format.  But there are some bugs in
18418fd37a7SXin LI      the standard: it says that we must print only the last component
18518fd37a7SXin LI      of the pathnames, and it requires two spaces after "diff" if
18618fd37a7SXin LI      there are no options.  These requirements are silly and do not
18718fd37a7SXin LI      match historical practice.  */
18818fd37a7SXin LI   sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
18918fd37a7SXin LI 
19018fd37a7SXin LI   if (paginate)
19118fd37a7SXin LI     {
19218fd37a7SXin LI       if (fflush (stdout) != 0)
19318fd37a7SXin LI 	pfatal_with_name (_("write failed"));
19418fd37a7SXin LI 
19518fd37a7SXin LI       /* Make OUTFILE a pipe to a subsidiary `pr'.  */
19618fd37a7SXin LI       {
19718fd37a7SXin LI #if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
19818fd37a7SXin LI 	int pipes[2];
19918fd37a7SXin LI 
20018fd37a7SXin LI 	if (pipe (pipes) != 0)
20118fd37a7SXin LI 	  pfatal_with_name ("pipe");
20218fd37a7SXin LI 
20318fd37a7SXin LI 	pr_pid = vfork ();
20418fd37a7SXin LI 	if (pr_pid < 0)
20518fd37a7SXin LI 	  pfatal_with_name ("fork");
20618fd37a7SXin LI 
20718fd37a7SXin LI 	if (pr_pid == 0)
20818fd37a7SXin LI 	  {
20918fd37a7SXin LI 	    close (pipes[1]);
21018fd37a7SXin LI 	    if (pipes[0] != STDIN_FILENO)
21118fd37a7SXin LI 	      {
21218fd37a7SXin LI 		if (dup2 (pipes[0], STDIN_FILENO) < 0)
21318fd37a7SXin LI 		  pfatal_with_name ("dup2");
21418fd37a7SXin LI 		close (pipes[0]);
21518fd37a7SXin LI 	      }
21618fd37a7SXin LI 
21718fd37a7SXin LI 	    execl (pr_program, pr_program, "-h", name, (char *) 0);
21818fd37a7SXin LI 	    _exit (errno == ENOENT ? 127 : 126);
21918fd37a7SXin LI 	  }
22018fd37a7SXin LI 	else
22118fd37a7SXin LI 	  {
22218fd37a7SXin LI 	    close (pipes[0]);
22318fd37a7SXin LI 	    outfile = fdopen (pipes[1], "w");
22418fd37a7SXin LI 	    if (!outfile)
22518fd37a7SXin LI 	      pfatal_with_name ("fdopen");
22618fd37a7SXin LI 	  }
22718fd37a7SXin LI #else
22818fd37a7SXin LI 	char *command = xmalloc (sizeof pr_program - 1 + 7
22918fd37a7SXin LI 				 + quote_system_arg ((char *) 0, name) + 1);
23018fd37a7SXin LI 	char *p;
23118fd37a7SXin LI 	sprintf (command, "%s -f -h ", pr_program);
23218fd37a7SXin LI 	p = command + sizeof pr_program - 1 + 7;
23318fd37a7SXin LI 	p += quote_system_arg (p, name);
23418fd37a7SXin LI 	*p = 0;
23518fd37a7SXin LI 	errno = 0;
23618fd37a7SXin LI 	outfile = popen (command, "w");
23718fd37a7SXin LI 	if (!outfile)
23818fd37a7SXin LI 	  pfatal_with_name (command);
23918fd37a7SXin LI 	free (command);
24018fd37a7SXin LI #endif
24118fd37a7SXin LI       }
24218fd37a7SXin LI     }
24318fd37a7SXin LI   else
24418fd37a7SXin LI     {
24518fd37a7SXin LI 
24618fd37a7SXin LI       /* If -l was not specified, output the diff straight to `stdout'.  */
24718fd37a7SXin LI 
24818fd37a7SXin LI       outfile = stdout;
24918fd37a7SXin LI 
25018fd37a7SXin LI       /* If handling multiple files (because scanning a directory),
25118fd37a7SXin LI 	 print which files the following output is about.  */
25218fd37a7SXin LI       if (currently_recursive)
25318fd37a7SXin LI 	printf ("%s\n", name);
25418fd37a7SXin LI     }
25518fd37a7SXin LI 
25618fd37a7SXin LI   free (name);
25718fd37a7SXin LI 
25818fd37a7SXin LI   /* A special header is needed at the beginning of context output.  */
25918fd37a7SXin LI   switch (output_style)
26018fd37a7SXin LI     {
26118fd37a7SXin LI     case OUTPUT_CONTEXT:
26218fd37a7SXin LI       print_context_header (files, false);
26318fd37a7SXin LI       break;
26418fd37a7SXin LI 
26518fd37a7SXin LI     case OUTPUT_UNIFIED:
26618fd37a7SXin LI       print_context_header (files, true);
26718fd37a7SXin LI       break;
26818fd37a7SXin LI 
26918fd37a7SXin LI     default:
27018fd37a7SXin LI       break;
27118fd37a7SXin LI     }
27218fd37a7SXin LI }
27318fd37a7SXin LI 
27418fd37a7SXin LI /* Call after the end of output of diffs for one file.
27518fd37a7SXin LI    Close OUTFILE and get rid of the `pr' subfork.  */
27618fd37a7SXin LI 
27718fd37a7SXin LI void
finish_output(void)27818fd37a7SXin LI finish_output (void)
27918fd37a7SXin LI {
28018fd37a7SXin LI   if (outfile != 0 && outfile != stdout)
28118fd37a7SXin LI     {
28218fd37a7SXin LI       int status;
28318fd37a7SXin LI       int wstatus;
28418fd37a7SXin LI       int werrno = 0;
28518fd37a7SXin LI       if (ferror (outfile))
28618fd37a7SXin LI 	fatal ("write failed");
28718fd37a7SXin LI #if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
28818fd37a7SXin LI       wstatus = pclose (outfile);
28918fd37a7SXin LI       if (wstatus == -1)
29018fd37a7SXin LI 	werrno = errno;
29118fd37a7SXin LI #else
29218fd37a7SXin LI       if (fclose (outfile) != 0)
29318fd37a7SXin LI 	pfatal_with_name (_("write failed"));
29418fd37a7SXin LI       if (waitpid (pr_pid, &wstatus, 0) < 0)
29518fd37a7SXin LI 	pfatal_with_name ("waitpid");
29618fd37a7SXin LI #endif
29718fd37a7SXin LI       status = (! werrno && WIFEXITED (wstatus)
29818fd37a7SXin LI 		? WEXITSTATUS (wstatus)
29918fd37a7SXin LI 		: INT_MAX);
30018fd37a7SXin LI       if (status)
30118fd37a7SXin LI 	error (EXIT_TROUBLE, werrno,
30218fd37a7SXin LI 	       _(status == 126
30318fd37a7SXin LI 		 ? "subsidiary program `%s' could not be invoked"
30418fd37a7SXin LI 		 : status == 127
30518fd37a7SXin LI 		 ? "subsidiary program `%s' not found"
30618fd37a7SXin LI 		 : status == INT_MAX
30718fd37a7SXin LI 		 ? "subsidiary program `%s' failed"
30818fd37a7SXin LI 		 : "subsidiary program `%s' failed (exit status %d)"),
30918fd37a7SXin LI 	       pr_program, status);
31018fd37a7SXin LI     }
31118fd37a7SXin LI 
31218fd37a7SXin LI   outfile = 0;
31318fd37a7SXin LI }
31418fd37a7SXin LI 
31518fd37a7SXin LI /* Compare two lines (typically one from each input file)
31618fd37a7SXin LI    according to the command line options.
31718fd37a7SXin LI    For efficiency, this is invoked only when the lines do not match exactly
31818fd37a7SXin LI    but an option like -i might cause us to ignore the difference.
31918fd37a7SXin LI    Return nonzero if the lines differ.  */
32018fd37a7SXin LI 
32118fd37a7SXin LI bool
lines_differ(char const * s1,char const * s2)32218fd37a7SXin LI lines_differ (char const *s1, char const *s2)
32318fd37a7SXin LI {
32418fd37a7SXin LI   register char const *t1 = s1;
32518fd37a7SXin LI   register char const *t2 = s2;
32618fd37a7SXin LI   size_t column = 0;
32718fd37a7SXin LI 
32818fd37a7SXin LI   while (1)
32918fd37a7SXin LI     {
33018fd37a7SXin LI       register unsigned char c1 = *t1++;
33118fd37a7SXin LI       register unsigned char c2 = *t2++;
33218fd37a7SXin LI 
33318fd37a7SXin LI       /* Test for exact char equality first, since it's a common case.  */
33418fd37a7SXin LI       if (c1 != c2)
33518fd37a7SXin LI 	{
33618fd37a7SXin LI 	  switch (ignore_white_space)
33718fd37a7SXin LI 	    {
33818fd37a7SXin LI 	    case IGNORE_ALL_SPACE:
33918fd37a7SXin LI 	      /* For -w, just skip past any white space.  */
34018fd37a7SXin LI 	      while (isspace (c1) && c1 != '\n') c1 = *t1++;
34118fd37a7SXin LI 	      while (isspace (c2) && c2 != '\n') c2 = *t2++;
34218fd37a7SXin LI 	      break;
34318fd37a7SXin LI 
34418fd37a7SXin LI 	    case IGNORE_SPACE_CHANGE:
34518fd37a7SXin LI 	      /* For -b, advance past any sequence of white space in
34618fd37a7SXin LI 		 line 1 and consider it just one space, or nothing at
34718fd37a7SXin LI 		 all if it is at the end of the line.  */
34818fd37a7SXin LI 	      if (isspace (c1))
34918fd37a7SXin LI 		{
35018fd37a7SXin LI 		  while (c1 != '\n')
35118fd37a7SXin LI 		    {
35218fd37a7SXin LI 		      c1 = *t1++;
35318fd37a7SXin LI 		      if (! isspace (c1))
35418fd37a7SXin LI 			{
35518fd37a7SXin LI 			  --t1;
35618fd37a7SXin LI 			  c1 = ' ';
35718fd37a7SXin LI 			  break;
35818fd37a7SXin LI 			}
35918fd37a7SXin LI 		    }
36018fd37a7SXin LI 		}
36118fd37a7SXin LI 
36218fd37a7SXin LI 	      /* Likewise for line 2.  */
36318fd37a7SXin LI 	      if (isspace (c2))
36418fd37a7SXin LI 		{
36518fd37a7SXin LI 		  while (c2 != '\n')
36618fd37a7SXin LI 		    {
36718fd37a7SXin LI 		      c2 = *t2++;
36818fd37a7SXin LI 		      if (! isspace (c2))
36918fd37a7SXin LI 			{
37018fd37a7SXin LI 			  --t2;
37118fd37a7SXin LI 			  c2 = ' ';
37218fd37a7SXin LI 			  break;
37318fd37a7SXin LI 			}
37418fd37a7SXin LI 		    }
37518fd37a7SXin LI 		}
37618fd37a7SXin LI 
37718fd37a7SXin LI 	      if (c1 != c2)
37818fd37a7SXin LI 		{
37918fd37a7SXin LI 		  /* If we went too far when doing the simple test
38018fd37a7SXin LI 		     for equality, go back to the first non-white-space
38118fd37a7SXin LI 		     character in both sides and try again.  */
38218fd37a7SXin LI 		  if (c2 == ' ' && c1 != '\n'
38318fd37a7SXin LI 		      && s1 + 1 < t1
38418fd37a7SXin LI 		      && isspace ((unsigned char) t1[-2]))
38518fd37a7SXin LI 		    {
38618fd37a7SXin LI 		      --t1;
38718fd37a7SXin LI 		      continue;
38818fd37a7SXin LI 		    }
38918fd37a7SXin LI 		  if (c1 == ' ' && c2 != '\n'
39018fd37a7SXin LI 		      && s2 + 1 < t2
39118fd37a7SXin LI 		      && isspace ((unsigned char) t2[-2]))
39218fd37a7SXin LI 		    {
39318fd37a7SXin LI 		      --t2;
39418fd37a7SXin LI 		      continue;
39518fd37a7SXin LI 		    }
39618fd37a7SXin LI 		}
39718fd37a7SXin LI 
39818fd37a7SXin LI 	      break;
39918fd37a7SXin LI 
40018fd37a7SXin LI 	    case IGNORE_TAB_EXPANSION:
40118fd37a7SXin LI 	      if ((c1 == ' ' && c2 == '\t')
40218fd37a7SXin LI 		  || (c1 == '\t' && c2 == ' '))
40318fd37a7SXin LI 		{
40418fd37a7SXin LI 		  size_t column2 = column;
40518fd37a7SXin LI 		  for (;; c1 = *t1++)
40618fd37a7SXin LI 		    {
40718fd37a7SXin LI 		      if (c1 == ' ')
40818fd37a7SXin LI 			column++;
40918fd37a7SXin LI 		      else if (c1 == '\t')
41018fd37a7SXin LI 			column += tabsize - column % tabsize;
41118fd37a7SXin LI 		      else
41218fd37a7SXin LI 			break;
41318fd37a7SXin LI 		    }
41418fd37a7SXin LI 		  for (;; c2 = *t2++)
41518fd37a7SXin LI 		    {
41618fd37a7SXin LI 		      if (c2 == ' ')
41718fd37a7SXin LI 			column2++;
41818fd37a7SXin LI 		      else if (c2 == '\t')
41918fd37a7SXin LI 			column2 += tabsize - column2 % tabsize;
42018fd37a7SXin LI 		      else
42118fd37a7SXin LI 			break;
42218fd37a7SXin LI 		    }
42318fd37a7SXin LI 		  if (column != column2)
42418fd37a7SXin LI 		    return true;
42518fd37a7SXin LI 		}
42618fd37a7SXin LI 	      break;
42718fd37a7SXin LI 
42818fd37a7SXin LI 	    case IGNORE_NO_WHITE_SPACE:
42918fd37a7SXin LI 	      break;
43018fd37a7SXin LI 	    }
43118fd37a7SXin LI 
43218fd37a7SXin LI 	  /* Lowercase all letters if -i is specified.  */
43318fd37a7SXin LI 
43418fd37a7SXin LI 	  if (ignore_case)
43518fd37a7SXin LI 	    {
43618fd37a7SXin LI 	      c1 = tolower (c1);
43718fd37a7SXin LI 	      c2 = tolower (c2);
43818fd37a7SXin LI 	    }
43918fd37a7SXin LI 
44018fd37a7SXin LI 	  if (c1 != c2)
44118fd37a7SXin LI 	    break;
44218fd37a7SXin LI 	}
44318fd37a7SXin LI       if (c1 == '\n')
44418fd37a7SXin LI 	return false;
44518fd37a7SXin LI 
44618fd37a7SXin LI       column += c1 == '\t' ? tabsize - column % tabsize : 1;
44718fd37a7SXin LI     }
44818fd37a7SXin LI 
44918fd37a7SXin LI   return true;
45018fd37a7SXin LI }
45118fd37a7SXin LI 
45218fd37a7SXin LI /* Find the consecutive changes at the start of the script START.
45318fd37a7SXin LI    Return the last link before the first gap.  */
45418fd37a7SXin LI 
45518fd37a7SXin LI struct change *
find_change(struct change * start)45618fd37a7SXin LI find_change (struct change *start)
45718fd37a7SXin LI {
45818fd37a7SXin LI   return start;
45918fd37a7SXin LI }
46018fd37a7SXin LI 
46118fd37a7SXin LI struct change *
find_reverse_change(struct change * start)46218fd37a7SXin LI find_reverse_change (struct change *start)
46318fd37a7SXin LI {
46418fd37a7SXin LI   return start;
46518fd37a7SXin LI }
46618fd37a7SXin LI 
46718fd37a7SXin LI /* Divide SCRIPT into pieces by calling HUNKFUN and
46818fd37a7SXin LI    print each piece with PRINTFUN.
46918fd37a7SXin LI    Both functions take one arg, an edit script.
47018fd37a7SXin LI 
47118fd37a7SXin LI    HUNKFUN is called with the tail of the script
47218fd37a7SXin LI    and returns the last link that belongs together with the start
47318fd37a7SXin LI    of the tail.
47418fd37a7SXin LI 
47518fd37a7SXin LI    PRINTFUN takes a subscript which belongs together (with a null
47618fd37a7SXin LI    link at the end) and prints it.  */
47718fd37a7SXin LI 
47818fd37a7SXin LI void
print_script(struct change * script,struct change * (* hunkfun)(struct change *),void (* printfun)(struct change *))47918fd37a7SXin LI print_script (struct change *script,
48018fd37a7SXin LI 	      struct change * (*hunkfun) (struct change *),
48118fd37a7SXin LI 	      void (*printfun) (struct change *))
48218fd37a7SXin LI {
48318fd37a7SXin LI   struct change *next = script;
48418fd37a7SXin LI 
48518fd37a7SXin LI   while (next)
48618fd37a7SXin LI     {
48718fd37a7SXin LI       struct change *this, *end;
48818fd37a7SXin LI 
48918fd37a7SXin LI       /* Find a set of changes that belong together.  */
49018fd37a7SXin LI       this = next;
49118fd37a7SXin LI       end = (*hunkfun) (next);
49218fd37a7SXin LI 
49318fd37a7SXin LI       /* Disconnect them from the rest of the changes,
49418fd37a7SXin LI 	 making them a hunk, and remember the rest for next iteration.  */
49518fd37a7SXin LI       next = end->link;
49618fd37a7SXin LI       end->link = 0;
49718fd37a7SXin LI #ifdef DEBUG
49818fd37a7SXin LI       debug_script (this);
49918fd37a7SXin LI #endif
50018fd37a7SXin LI 
50118fd37a7SXin LI       /* Print this hunk.  */
50218fd37a7SXin LI       (*printfun) (this);
50318fd37a7SXin LI 
50418fd37a7SXin LI       /* Reconnect the script so it will all be freed properly.  */
50518fd37a7SXin LI       end->link = next;
50618fd37a7SXin LI     }
50718fd37a7SXin LI }
50818fd37a7SXin LI 
50918fd37a7SXin LI /* Print the text of a single line LINE,
51018fd37a7SXin LI    flagging it with the characters in LINE_FLAG (which say whether
51118fd37a7SXin LI    the line is inserted, deleted, changed, etc.).  */
51218fd37a7SXin LI 
51318fd37a7SXin LI void
print_1_line(char const * line_flag,char const * const * line)51418fd37a7SXin LI print_1_line (char const *line_flag, char const *const *line)
51518fd37a7SXin LI {
51618fd37a7SXin LI   char const *base = line[0], *limit = line[1]; /* Help the compiler.  */
51718fd37a7SXin LI   FILE *out = outfile; /* Help the compiler some more.  */
51818fd37a7SXin LI   char const *flag_format = 0;
51918fd37a7SXin LI 
52018fd37a7SXin LI   /* If -T was specified, use a Tab between the line-flag and the text.
52118fd37a7SXin LI      Otherwise use a Space (as Unix diff does).
52218fd37a7SXin LI      Print neither space nor tab if line-flags are empty.  */
52318fd37a7SXin LI 
52418fd37a7SXin LI   if (line_flag && *line_flag)
52518fd37a7SXin LI     {
52618fd37a7SXin LI       flag_format = initial_tab ? "%s\t" : "%s ";
52718fd37a7SXin LI       fprintf (out, flag_format, line_flag);
52818fd37a7SXin LI     }
52918fd37a7SXin LI 
53018fd37a7SXin LI   output_1_line (base, limit, flag_format, line_flag);
53118fd37a7SXin LI 
53218fd37a7SXin LI   if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
53318fd37a7SXin LI     fprintf (out, "\n\\ %s\n", _("No newline at end of file"));
53418fd37a7SXin LI }
53518fd37a7SXin LI 
53618fd37a7SXin LI /* Output a line from BASE up to LIMIT.
53718fd37a7SXin LI    With -t, expand white space characters to spaces, and if FLAG_FORMAT
53818fd37a7SXin LI    is nonzero, output it with argument LINE_FLAG after every
53918fd37a7SXin LI    internal carriage return, so that tab stops continue to line up.  */
54018fd37a7SXin LI 
54118fd37a7SXin LI void
output_1_line(char const * base,char const * limit,char const * flag_format,char const * line_flag)54218fd37a7SXin LI output_1_line (char const *base, char const *limit, char const *flag_format,
54318fd37a7SXin LI 	       char const *line_flag)
54418fd37a7SXin LI {
54518fd37a7SXin LI   if (!expand_tabs)
54618fd37a7SXin LI     fwrite (base, sizeof (char), limit - base, outfile);
54718fd37a7SXin LI   else
54818fd37a7SXin LI     {
54918fd37a7SXin LI       register FILE *out = outfile;
55018fd37a7SXin LI       register unsigned char c;
55118fd37a7SXin LI       register char const *t = base;
55218fd37a7SXin LI       register size_t column = 0;
55318fd37a7SXin LI       size_t tab_size = tabsize;
55418fd37a7SXin LI 
55518fd37a7SXin LI       while (t < limit)
55618fd37a7SXin LI 	switch ((c = *t++))
55718fd37a7SXin LI 	  {
55818fd37a7SXin LI 	  case '\t':
55918fd37a7SXin LI 	    {
56018fd37a7SXin LI 	      size_t spaces = tab_size - column % tab_size;
56118fd37a7SXin LI 	      column += spaces;
56218fd37a7SXin LI 	      do
56318fd37a7SXin LI 		putc (' ', out);
56418fd37a7SXin LI 	      while (--spaces);
56518fd37a7SXin LI 	    }
56618fd37a7SXin LI 	    break;
56718fd37a7SXin LI 
56818fd37a7SXin LI 	  case '\r':
56918fd37a7SXin LI 	    putc (c, out);
57018fd37a7SXin LI 	    if (flag_format && t < limit && *t != '\n')
57118fd37a7SXin LI 	      fprintf (out, flag_format, line_flag);
57218fd37a7SXin LI 	    column = 0;
57318fd37a7SXin LI 	    break;
57418fd37a7SXin LI 
57518fd37a7SXin LI 	  case '\b':
57618fd37a7SXin LI 	    if (column == 0)
57718fd37a7SXin LI 	      continue;
57818fd37a7SXin LI 	    column--;
57918fd37a7SXin LI 	    putc (c, out);
58018fd37a7SXin LI 	    break;
58118fd37a7SXin LI 
58218fd37a7SXin LI 	  default:
58318fd37a7SXin LI 	    column += isprint (c) != 0;
58418fd37a7SXin LI 	    putc (c, out);
58518fd37a7SXin LI 	    break;
58618fd37a7SXin LI 	  }
58718fd37a7SXin LI     }
58818fd37a7SXin LI }
58918fd37a7SXin LI 
59018fd37a7SXin LI char const change_letter[] = { 0, 'd', 'a', 'c' };
59118fd37a7SXin LI 
59218fd37a7SXin LI /* Translate an internal line number (an index into diff's table of lines)
59318fd37a7SXin LI    into an actual line number in the input file.
59418fd37a7SXin LI    The internal line number is I.  FILE points to the data on the file.
59518fd37a7SXin LI 
59618fd37a7SXin LI    Internal line numbers count from 0 starting after the prefix.
59718fd37a7SXin LI    Actual line numbers count from 1 within the entire file.  */
59818fd37a7SXin LI 
59918fd37a7SXin LI lin
translate_line_number(struct file_data const * file,lin i)60018fd37a7SXin LI translate_line_number (struct file_data const *file, lin i)
60118fd37a7SXin LI {
60218fd37a7SXin LI   return i + file->prefix_lines + 1;
60318fd37a7SXin LI }
60418fd37a7SXin LI 
60518fd37a7SXin LI /* Translate a line number range.  This is always done for printing,
60618fd37a7SXin LI    so for convenience translate to long int rather than lin, so that the
60718fd37a7SXin LI    caller can use printf with "%ld" without casting.  */
60818fd37a7SXin LI 
60918fd37a7SXin LI void
translate_range(struct file_data const * file,lin a,lin b,long int * aptr,long int * bptr)61018fd37a7SXin LI translate_range (struct file_data const *file,
61118fd37a7SXin LI 		 lin a, lin b,
61218fd37a7SXin LI 		 long int *aptr, long int *bptr)
61318fd37a7SXin LI {
61418fd37a7SXin LI   *aptr = translate_line_number (file, a - 1) + 1;
61518fd37a7SXin LI   *bptr = translate_line_number (file, b + 1) - 1;
61618fd37a7SXin LI }
61718fd37a7SXin LI 
61818fd37a7SXin LI /* Print a pair of line numbers with SEPCHAR, translated for file FILE.
61918fd37a7SXin LI    If the two numbers are identical, print just one number.
62018fd37a7SXin LI 
62118fd37a7SXin LI    Args A and B are internal line numbers.
62218fd37a7SXin LI    We print the translated (real) line numbers.  */
62318fd37a7SXin LI 
62418fd37a7SXin LI void
print_number_range(char sepchar,struct file_data * file,lin a,lin b)62518fd37a7SXin LI print_number_range (char sepchar, struct file_data *file, lin a, lin b)
62618fd37a7SXin LI {
62718fd37a7SXin LI   long int trans_a, trans_b;
62818fd37a7SXin LI   translate_range (file, a, b, &trans_a, &trans_b);
62918fd37a7SXin LI 
63018fd37a7SXin LI   /* Note: we can have B < A in the case of a range of no lines.
63118fd37a7SXin LI      In this case, we should print the line number before the range,
63218fd37a7SXin LI      which is B.  */
63318fd37a7SXin LI   if (trans_b > trans_a)
63418fd37a7SXin LI     fprintf (outfile, "%ld%c%ld", trans_a, sepchar, trans_b);
63518fd37a7SXin LI   else
63618fd37a7SXin LI     fprintf (outfile, "%ld", trans_b);
63718fd37a7SXin LI }
63818fd37a7SXin LI 
63918fd37a7SXin LI /* Look at a hunk of edit script and report the range of lines in each file
64018fd37a7SXin LI    that it applies to.  HUNK is the start of the hunk, which is a chain
64118fd37a7SXin LI    of `struct change'.  The first and last line numbers of file 0 are stored in
64218fd37a7SXin LI    *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
64318fd37a7SXin LI    Note that these are internal line numbers that count from 0.
64418fd37a7SXin LI 
64518fd37a7SXin LI    If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
64618fd37a7SXin LI 
64718fd37a7SXin LI    Return UNCHANGED if only ignorable lines are inserted or deleted,
64818fd37a7SXin LI    OLD if lines of file 0 are deleted,
64918fd37a7SXin LI    NEW if lines of file 1 are inserted,
65018fd37a7SXin LI    and CHANGED if both kinds of changes are found. */
65118fd37a7SXin LI 
65218fd37a7SXin LI enum changes
analyze_hunk(struct change * hunk,lin * first0,lin * last0,lin * first1,lin * last1)65318fd37a7SXin LI analyze_hunk (struct change *hunk,
65418fd37a7SXin LI 	      lin *first0, lin *last0,
65518fd37a7SXin LI 	      lin *first1, lin *last1)
65618fd37a7SXin LI {
65718fd37a7SXin LI   struct change *next;
65818fd37a7SXin LI   lin l0, l1;
65918fd37a7SXin LI   lin show_from, show_to;
66018fd37a7SXin LI   lin i;
66118fd37a7SXin LI   bool trivial = ignore_blank_lines || ignore_regexp.fastmap;
66218fd37a7SXin LI   size_t trivial_length = ignore_blank_lines - 1;
66318fd37a7SXin LI     /* If 0, ignore zero-length lines;
66418fd37a7SXin LI        if SIZE_MAX, do not ignore lines just because of their length.  */
66518fd37a7SXin LI   bool skip_leading_white_space =
66618fd37a7SXin LI     (ignore_blank_lines && IGNORE_SPACE_CHANGE <= ignore_white_space);
66718fd37a7SXin LI 
66818fd37a7SXin LI   char const * const *linbuf0 = files[0].linbuf;  /* Help the compiler.  */
66918fd37a7SXin LI   char const * const *linbuf1 = files[1].linbuf;
67018fd37a7SXin LI 
67118fd37a7SXin LI   show_from = show_to = 0;
67218fd37a7SXin LI 
67318fd37a7SXin LI   *first0 = hunk->line0;
67418fd37a7SXin LI   *first1 = hunk->line1;
67518fd37a7SXin LI 
67618fd37a7SXin LI   next = hunk;
67718fd37a7SXin LI   do
67818fd37a7SXin LI     {
67918fd37a7SXin LI       l0 = next->line0 + next->deleted - 1;
68018fd37a7SXin LI       l1 = next->line1 + next->inserted - 1;
68118fd37a7SXin LI       show_from += next->deleted;
68218fd37a7SXin LI       show_to += next->inserted;
68318fd37a7SXin LI 
68418fd37a7SXin LI       for (i = next->line0; i <= l0 && trivial; i++)
68518fd37a7SXin LI 	{
68618fd37a7SXin LI 	  char const *line = linbuf0[i];
68718fd37a7SXin LI 	  char const *newline = linbuf0[i + 1] - 1;
68818fd37a7SXin LI 	  size_t len = newline - line;
68918fd37a7SXin LI 	  char const *p = line;
69018fd37a7SXin LI 	  if (skip_leading_white_space)
69118fd37a7SXin LI 	    while (isspace ((unsigned char) *p) && *p != '\n')
69218fd37a7SXin LI 	      p++;
69318fd37a7SXin LI 	  if (newline - p != trivial_length
69418fd37a7SXin LI 	      && (! ignore_regexp.fastmap
69518fd37a7SXin LI 		  || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
69618fd37a7SXin LI 	    trivial = 0;
69718fd37a7SXin LI 	}
69818fd37a7SXin LI 
69918fd37a7SXin LI       for (i = next->line1; i <= l1 && trivial; i++)
70018fd37a7SXin LI 	{
70118fd37a7SXin LI 	  char const *line = linbuf1[i];
70218fd37a7SXin LI 	  char const *newline = linbuf1[i + 1] - 1;
70318fd37a7SXin LI 	  size_t len = newline - line;
70418fd37a7SXin LI 	  char const *p = line;
70518fd37a7SXin LI 	  if (skip_leading_white_space)
70618fd37a7SXin LI 	    while (isspace ((unsigned char) *p) && *p != '\n')
70718fd37a7SXin LI 	      p++;
70818fd37a7SXin LI 	  if (newline - p != trivial_length
70918fd37a7SXin LI 	      && (! ignore_regexp.fastmap
71018fd37a7SXin LI 		  || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
71118fd37a7SXin LI 	    trivial = 0;
71218fd37a7SXin LI 	}
71318fd37a7SXin LI     }
71418fd37a7SXin LI   while ((next = next->link) != 0);
71518fd37a7SXin LI 
71618fd37a7SXin LI   *last0 = l0;
71718fd37a7SXin LI   *last1 = l1;
71818fd37a7SXin LI 
71918fd37a7SXin LI   /* If all inserted or deleted lines are ignorable,
72018fd37a7SXin LI      tell the caller to ignore this hunk.  */
72118fd37a7SXin LI 
72218fd37a7SXin LI   if (trivial)
72318fd37a7SXin LI     return UNCHANGED;
72418fd37a7SXin LI 
72518fd37a7SXin LI   return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED);
72618fd37a7SXin LI }
72718fd37a7SXin LI 
72818fd37a7SXin LI /* Concatenate three strings, returning a newly malloc'd string.  */
72918fd37a7SXin LI 
73018fd37a7SXin LI char *
concat(char const * s1,char const * s2,char const * s3)73118fd37a7SXin LI concat (char const *s1, char const *s2, char const *s3)
73218fd37a7SXin LI {
73318fd37a7SXin LI   char *new = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
73418fd37a7SXin LI   sprintf (new, "%s%s%s", s1, s2, s3);
73518fd37a7SXin LI   return new;
73618fd37a7SXin LI }
73718fd37a7SXin LI 
73818fd37a7SXin LI /* Yield a new block of SIZE bytes, initialized to zero.  */
73918fd37a7SXin LI 
74018fd37a7SXin LI void *
zalloc(size_t size)74118fd37a7SXin LI zalloc (size_t size)
74218fd37a7SXin LI {
74318fd37a7SXin LI   void *p = xmalloc (size);
74418fd37a7SXin LI   memset (p, 0, size);
74518fd37a7SXin LI   return p;
74618fd37a7SXin LI }
74718fd37a7SXin LI 
74818fd37a7SXin LI /* Yield the newly malloc'd pathname
74918fd37a7SXin LI    of the file in DIR whose filename is FILE.  */
75018fd37a7SXin LI 
75118fd37a7SXin LI char *
dir_file_pathname(char const * dir,char const * file)75218fd37a7SXin LI dir_file_pathname (char const *dir, char const *file)
75318fd37a7SXin LI {
75418fd37a7SXin LI   char const *base = base_name (dir);
75518fd37a7SXin LI   bool omit_slash = !*base || base[strlen (base) - 1] == '/';
75618fd37a7SXin LI   return concat (dir, "/" + omit_slash, file);
75718fd37a7SXin LI }
75818fd37a7SXin LI 
75918fd37a7SXin LI void
debug_script(struct change * sp)76018fd37a7SXin LI debug_script (struct change *sp)
76118fd37a7SXin LI {
76218fd37a7SXin LI   fflush (stdout);
76318fd37a7SXin LI 
76418fd37a7SXin LI   for (; sp; sp = sp->link)
76518fd37a7SXin LI     {
76618fd37a7SXin LI       long int line0 = sp->line0;
76718fd37a7SXin LI       long int line1 = sp->line1;
76818fd37a7SXin LI       long int deleted = sp->deleted;
76918fd37a7SXin LI       long int inserted = sp->inserted;
77018fd37a7SXin LI       fprintf (stderr, "%3ld %3ld delete %ld insert %ld\n",
77118fd37a7SXin LI 	       line0, line1, deleted, inserted);
77218fd37a7SXin LI     }
77318fd37a7SXin LI 
77418fd37a7SXin LI   fflush (stderr);
77518fd37a7SXin LI }
776