summaryrefslogtreecommitdiff
path: root/gnu/dist/diffutils/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/dist/diffutils/src/util.c')
-rw-r--r--gnu/dist/diffutils/src/util.c758
1 files changed, 0 insertions, 758 deletions
diff --git a/gnu/dist/diffutils/src/util.c b/gnu/dist/diffutils/src/util.c
deleted file mode 100644
index 0208c7efb18..00000000000
--- a/gnu/dist/diffutils/src/util.c
+++ /dev/null
@@ -1,758 +0,0 @@
-/* $NetBSD: util.c,v 1.1.1.1 2003/01/26 00:43:17 wiz Exp $ */
-
-/* Support routines for GNU DIFF.
-
- Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002
- Free Software Foundation, Inc.
-
- This file is part of GNU DIFF.
-
- GNU DIFF is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GNU DIFF is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING.
- If not, write to the Free Software Foundation,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "diff.h"
-#include <dirname.h>
-#include <error.h>
-#include <quotesys.h>
-#include <regex.h>
-#include <xalloc.h>
-
-char const pr_program[] = PR_PROGRAM;
-
-/* Queue up one-line messages to be printed at the end,
- when -l is specified. Each message is recorded with a `struct msg'. */
-
-struct msg
-{
- struct msg *next;
- char args[1]; /* Format + 4 args, each '\0' terminated, concatenated. */
-};
-
-/* Head of the chain of queues messages. */
-
-static struct msg *msg_chain;
-
-/* Tail of the chain of queues messages. */
-
-static struct msg **msg_chain_end = &msg_chain;
-
-/* Use when a system call returns non-zero status.
- NAME should normally be the file name. */
-
-void
-perror_with_name (char const *name)
-{
- error (0, errno, "%s", name);
-}
-
-/* Use when a system call returns non-zero status and that is fatal. */
-
-void
-pfatal_with_name (char const *name)
-{
- int e = errno;
- print_message_queue ();
- error (EXIT_TROUBLE, e, "%s", name);
- abort ();
-}
-
-/* Print an error message containing MSGID, then exit. */
-
-void
-fatal (char const *msgid)
-{
- print_message_queue ();
- error (EXIT_TROUBLE, 0, "%s", _(msgid));
- abort ();
-}
-
-/* Like printf, except if -l in effect then save the message and print later.
- This is used for things like "Only in ...". */
-
-void
-message (char const *format_msgid, char const *arg1, char const *arg2)
-{
- message5 (format_msgid, arg1, arg2, 0, 0);
-}
-
-void
-message5 (char const *format_msgid, char const *arg1, char const *arg2,
- char const *arg3, char const *arg4)
-{
- if (paginate)
- {
- char *p;
- char const *arg[5];
- int i;
- size_t size[5];
- size_t total_size = offsetof (struct msg, args);
- struct msg *new;
-
- arg[0] = format_msgid;
- arg[1] = arg1;
- arg[2] = arg2;
- arg[3] = arg3 ? arg3 : "";
- arg[4] = arg4 ? arg4 : "";
-
- for (i = 0; i < 5; i++)
- total_size += size[i] = strlen (arg[i]) + 1;
-
- new = xmalloc (total_size);
-
- for (i = 0, p = new->args; i < 5; p += size[i++])
- memcpy (p, arg[i], size[i]);
-
- *msg_chain_end = new;
- new->next = 0;
- msg_chain_end = &new->next;
- }
- else
- {
- if (sdiff_merge_assist)
- putchar (' ');
- printf (_(format_msgid), arg1, arg2, arg3, arg4);
- }
-}
-
-/* Output all the messages that were saved up by calls to `message'. */
-
-void
-print_message_queue (void)
-{
- char const *arg[5];
- int i;
- struct msg *m = msg_chain;
-
- while (m)
- {
- struct msg *next = m->next;
- arg[0] = m->args;
- for (i = 0; i < 4; i++)
- arg[i + 1] = arg[i] + strlen (arg[i]) + 1;
- printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]);
- free (m);
- m = next;
- }
-}
-
-/* Call before outputting the results of comparing files NAME0 and NAME1
- to set up OUTFILE, the stdio stream for the output to go to.
-
- Usually, OUTFILE is just stdout. But when -l was specified
- we fork off a `pr' and make OUTFILE a pipe to it.
- `pr' then outputs to our stdout. */
-
-static char const *current_name0;
-static char const *current_name1;
-static bool currently_recursive;
-
-void
-setup_output (char const *name0, char const *name1, bool recursive)
-{
- current_name0 = name0;
- current_name1 = name1;
- currently_recursive = recursive;
- outfile = 0;
-}
-
-#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
-static pid_t pr_pid;
-#endif
-
-void
-begin_output (void)
-{
- char *name;
-
- if (outfile != 0)
- return;
-
- /* Construct the header of this piece of diff. */
- name = xmalloc (strlen (current_name0) + strlen (current_name1)
- + strlen (switch_string) + 7);
-
- /* POSIX 1003.1-2001 specifies this format. But there are some bugs in
- the standard: it says that we must print only the last component
- of the pathnames, and it requires two spaces after "diff" if
- there are no options. These requirements are silly and do not
- match historical practice. */
- sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1);
-
- if (paginate)
- {
- if (fflush (stdout) != 0)
- pfatal_with_name (_("write failed"));
-
- /* Make OUTFILE a pipe to a subsidiary `pr'. */
- {
-#if HAVE_WORKING_FORK || HAVE_WORKING_VFORK
- int pipes[2];
-
- if (pipe (pipes) != 0)
- pfatal_with_name ("pipe");
-
- pr_pid = vfork ();
- if (pr_pid < 0)
- pfatal_with_name ("fork");
-
- if (pr_pid == 0)
- {
- close (pipes[1]);
- if (pipes[0] != STDIN_FILENO)
- {
- if (dup2 (pipes[0], STDIN_FILENO) < 0)
- pfatal_with_name ("dup2");
- close (pipes[0]);
- }
-
- execl (pr_program, pr_program, "-h", name, 0);
- _exit (errno == ENOEXEC ? 126 : 127);
- }
- else
- {
- close (pipes[0]);
- outfile = fdopen (pipes[1], "w");
- if (!outfile)
- pfatal_with_name ("fdopen");
- }
-#else
- char *command = xmalloc (sizeof pr_program - 1 + 7
- + quote_system_arg ((char *) 0, name) + 1);
- char *p;
- sprintf (command, "%s -f -h ", pr_program);
- p = command + sizeof pr_program - 1 + 7;
- p += quote_system_arg (p, name);
- *p = 0;
- errno = 0;
- outfile = popen (command, "w");
- if (!outfile)
- pfatal_with_name (command);
- free (command);
-#endif
- }
- }
- else
- {
-
- /* If -l was not specified, output the diff straight to `stdout'. */
-
- outfile = stdout;
-
- /* If handling multiple files (because scanning a directory),
- print which files the following output is about. */
- if (currently_recursive)
- printf ("%s\n", name);
- }
-
- free (name);
-
- /* A special header is needed at the beginning of context output. */
- switch (output_style)
- {
- case OUTPUT_CONTEXT:
- print_context_header (files, 0);
- break;
-
- case OUTPUT_UNIFIED:
- print_context_header (files, 1);
- break;
-
- default:
- break;
- }
-}
-
-/* Call after the end of output of diffs for one file.
- Close OUTFILE and get rid of the `pr' subfork. */
-
-void
-finish_output (void)
-{
- if (outfile != 0 && outfile != stdout)
- {
- int wstatus;
- int werrno = 0;
- if (ferror (outfile))
- fatal ("write failed");
-#if ! (HAVE_WORKING_FORK || HAVE_WORKING_VFORK)
- wstatus = pclose (outfile);
- if (wstatus == -1)
- werrno = errno;
-#else
- if (fclose (outfile) != 0)
- pfatal_with_name (_("write failed"));
- if (waitpid (pr_pid, &wstatus, 0) < 0)
- pfatal_with_name ("waitpid");
-#endif
- if (! werrno && WIFEXITED (wstatus) && WEXITSTATUS (wstatus) == 127)
- error (EXIT_TROUBLE, 0, _("subsidiary program `%s' not found"),
- pr_program);
- if (wstatus != 0)
- error (EXIT_TROUBLE, werrno, _("subsidiary program `%s' failed"),
- pr_program);
- }
-
- outfile = 0;
-}
-
-/* Compare two lines (typically one from each input file)
- according to the command line options.
- For efficiency, this is invoked only when the lines do not match exactly
- but an option like -i might cause us to ignore the difference.
- Return nonzero if the lines differ. */
-
-bool
-lines_differ (char const *s1, char const *s2)
-{
- register unsigned char const *t1 = (unsigned char const *) s1;
- register unsigned char const *t2 = (unsigned char const *) s2;
- size_t column = 0;
-
- while (1)
- {
- register unsigned char c1 = *t1++;
- register unsigned char c2 = *t2++;
-
- /* Test for exact char equality first, since it's a common case. */
- if (c1 != c2)
- {
- switch (ignore_white_space)
- {
- case IGNORE_ALL_SPACE:
- /* For -w, just skip past any white space. */
- while (ISSPACE (c1) && c1 != '\n') c1 = *t1++;
- while (ISSPACE (c2) && c2 != '\n') c2 = *t2++;
- break;
-
- case IGNORE_SPACE_CHANGE:
- /* For -b, advance past any sequence of white space in
- line 1 and consider it just one space, or nothing at
- all if it is at the end of the line. */
- if (ISSPACE (c1))
- {
- while (c1 != '\n')
- {
- c1 = *t1++;
- if (! ISSPACE (c1))
- {
- --t1;
- c1 = ' ';
- break;
- }
- }
- }
-
- /* Likewise for line 2. */
- if (ISSPACE (c2))
- {
- while (c2 != '\n')
- {
- c2 = *t2++;
- if (! ISSPACE (c2))
- {
- --t2;
- c2 = ' ';
- break;
- }
- }
- }
-
- if (c1 != c2)
- {
- /* If we went too far when doing the simple test
- for equality, go back to the first non-white-space
- character in both sides and try again. */
- if (c2 == ' ' && c1 != '\n'
- && (unsigned char const *) s1 + 1 < t1
- && ISSPACE (t1[-2]))
- {
- --t1;
- continue;
- }
- if (c1 == ' ' && c2 != '\n'
- && (unsigned char const *) s2 + 1 < t2
- && ISSPACE (t2[-2]))
- {
- --t2;
- continue;
- }
- }
-
- break;
-
- case IGNORE_TAB_EXPANSION:
- if ((c1 == ' ' && c2 == '\t')
- || (c1 == '\t' && c2 == ' '))
- {
- size_t column2 = column;
- for (;; c1 = *t1++)
- {
- if (c1 == ' ')
- column++;
- else if (c1 == '\t')
- column += TAB_WIDTH - column % TAB_WIDTH;
- else
- break;
- }
- for (;; c2 = *t2++)
- {
- if (c2 == ' ')
- column2++;
- else if (c2 == '\t')
- column2 += TAB_WIDTH - column2 % TAB_WIDTH;
- else
- break;
- }
- if (column != column2)
- return 1;
- }
- break;
-
- case IGNORE_NO_WHITE_SPACE:
- break;
- }
-
- /* Lowercase all letters if -i is specified. */
-
- if (ignore_case)
- {
- c1 = TOLOWER (c1);
- c2 = TOLOWER (c2);
- }
-
- if (c1 != c2)
- break;
- }
- if (c1 == '\n')
- return 0;
-
- column += c1 == '\t' ? TAB_WIDTH - column % TAB_WIDTH : 1;
- }
-
- return 1;
-}
-
-/* Find the consecutive changes at the start of the script START.
- Return the last link before the first gap. */
-
-struct change *
-find_change (struct change *start)
-{
- return start;
-}
-
-struct change *
-find_reverse_change (struct change *start)
-{
- return start;
-}
-
-/* Divide SCRIPT into pieces by calling HUNKFUN and
- print each piece with PRINTFUN.
- Both functions take one arg, an edit script.
-
- HUNKFUN is called with the tail of the script
- and returns the last link that belongs together with the start
- of the tail.
-
- PRINTFUN takes a subscript which belongs together (with a null
- link at the end) and prints it. */
-
-void
-print_script (struct change *script,
- struct change * (*hunkfun) (struct change *),
- void (*printfun) (struct change *))
-{
- struct change *next = script;
-
- while (next)
- {
- struct change *this, *end;
-
- /* Find a set of changes that belong together. */
- this = next;
- end = (*hunkfun) (next);
-
- /* Disconnect them from the rest of the changes,
- making them a hunk, and remember the rest for next iteration. */
- next = end->link;
- end->link = 0;
-#ifdef DEBUG
- debug_script (this);
-#endif
-
- /* Print this hunk. */
- (*printfun) (this);
-
- /* Reconnect the script so it will all be freed properly. */
- end->link = next;
- }
-}
-
-/* Print the text of a single line LINE,
- flagging it with the characters in LINE_FLAG (which say whether
- the line is inserted, deleted, changed, etc.). */
-
-void
-print_1_line (char const *line_flag, char const *const *line)
-{
- char const *base = line[0], *limit = line[1]; /* Help the compiler. */
- FILE *out = outfile; /* Help the compiler some more. */
- char const *flag_format = 0;
-
- /* If -T was specified, use a Tab between the line-flag and the text.
- Otherwise use a Space (as Unix diff does).
- Print neither space nor tab if line-flags are empty. */
-
- if (line_flag && *line_flag)
- {
- flag_format = initial_tab ? "%s\t" : "%s ";
- fprintf (out, flag_format, line_flag);
- }
-
- output_1_line (base, limit, flag_format, line_flag);
-
- if ((!line_flag || line_flag[0]) && limit[-1] != '\n')
- fprintf (out, "\n\\ %s\n", _("No newline at end of file"));
-}
-
-/* Output a line from BASE up to LIMIT.
- With -t, expand white space characters to spaces, and if FLAG_FORMAT
- is nonzero, output it with argument LINE_FLAG after every
- internal carriage return, so that tab stops continue to line up. */
-
-void
-output_1_line (char const *base, char const *limit, char const *flag_format,
- char const *line_flag)
-{
- if (!expand_tabs)
- fwrite (base, limit - base, 1, outfile);
- else
- {
- register FILE *out = outfile;
- register unsigned char c;
- register char const *t = base;
- register unsigned int column = 0;
-
- while (t < limit)
- switch ((c = *t++))
- {
- case '\t':
- {
- unsigned int spaces = TAB_WIDTH - column % TAB_WIDTH;
- column += spaces;
- do
- putc (' ', out);
- while (--spaces);
- }
- break;
-
- case '\r':
- putc (c, out);
- if (flag_format && t < limit && *t != '\n')
- fprintf (out, flag_format, line_flag);
- column = 0;
- break;
-
- case '\b':
- if (column == 0)
- continue;
- column--;
- putc (c, out);
- break;
-
- default:
- if (ISPRINT (c))
- column++;
- putc (c, out);
- break;
- }
- }
-}
-
-char const change_letter[] = { 0, 'd', 'a', 'c' };
-
-/* Translate an internal line number (an index into diff's table of lines)
- into an actual line number in the input file.
- The internal line number is I. FILE points to the data on the file.
-
- Internal line numbers count from 0 starting after the prefix.
- Actual line numbers count from 1 within the entire file. */
-
-lin
-translate_line_number (struct file_data const *file, lin i)
-{
- return i + file->prefix_lines + 1;
-}
-
-/* Translate a line number range. This is always done for printing,
- so for convenience translate to long rather than lin, so that the
- caller can use printf with "%ld" without casting. */
-
-void
-translate_range (struct file_data const *file,
- lin a, lin b,
- long *aptr, long *bptr)
-{
- *aptr = translate_line_number (file, a - 1) + 1;
- *bptr = translate_line_number (file, b + 1) - 1;
-}
-
-/* Print a pair of line numbers with SEPCHAR, translated for file FILE.
- If the two numbers are identical, print just one number.
-
- Args A and B are internal line numbers.
- We print the translated (real) line numbers. */
-
-void
-print_number_range (char sepchar, struct file_data *file, lin a, lin b)
-{
- long trans_a, trans_b;
- translate_range (file, a, b, &trans_a, &trans_b);
-
- /* Note: we can have B < A in the case of a range of no lines.
- In this case, we should print the line number before the range,
- which is B. */
- if (trans_b > trans_a)
- fprintf (outfile, "%ld%c%ld", trans_a, sepchar, trans_b);
- else
- fprintf (outfile, "%ld", trans_b);
-}
-
-/* Look at a hunk of edit script and report the range of lines in each file
- that it applies to. HUNK is the start of the hunk, which is a chain
- of `struct change'. The first and last line numbers of file 0 are stored in
- *FIRST0 and *LAST0, and likewise for file 1 in *FIRST1 and *LAST1.
- Note that these are internal line numbers that count from 0.
-
- If no lines from file 0 are deleted, then FIRST0 is LAST0+1.
-
- Return UNCHANGED if only ignorable lines are inserted or deleted,
- OLD if lines of file 0 are deleted,
- NEW if lines of file 1 are inserted,
- and CHANGED if both kinds of changes are found. */
-
-enum changes
-analyze_hunk (struct change *hunk,
- lin *first0, lin *last0,
- lin *first1, lin *last1)
-{
- struct change *next;
- lin l0, l1;
- lin show_from, show_to;
- lin i;
- bool trivial = ignore_blank_lines || ignore_regexp.fastmap;
- size_t trivial_length = (int) ignore_blank_lines - 1;
- /* If 0, ignore zero-length lines;
- if SIZE_MAX, do not ignore lines just because of their length. */
-
- char const * const *linbuf0 = files[0].linbuf; /* Help the compiler. */
- char const * const *linbuf1 = files[1].linbuf;
-
- show_from = show_to = 0;
-
- *first0 = hunk->line0;
- *first1 = hunk->line1;
-
- next = hunk;
- do
- {
- l0 = next->line0 + next->deleted - 1;
- l1 = next->line1 + next->inserted - 1;
- show_from += next->deleted;
- show_to += next->inserted;
-
- for (i = next->line0; i <= l0 && trivial; i++)
- {
- char const *line = linbuf0[i];
- size_t len = linbuf0[i + 1] - line - 1;
- if (len != trivial_length
- && (! ignore_regexp.fastmap
- || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
- trivial = 0;
- }
-
- for (i = next->line1; i <= l1 && trivial; i++)
- {
- char const *line = linbuf1[i];
- size_t len = linbuf1[i + 1] - line - 1;
- if (len != trivial_length
- && (! ignore_regexp.fastmap
- || re_search (&ignore_regexp, line, len, 0, len, 0) < 0))
- trivial = 0;
- }
- }
- while ((next = next->link) != 0);
-
- *last0 = l0;
- *last1 = l1;
-
- /* If all inserted or deleted lines are ignorable,
- tell the caller to ignore this hunk. */
-
- if (trivial)
- return UNCHANGED;
-
- return (show_from ? OLD : UNCHANGED) | (show_to ? NEW : UNCHANGED);
-}
-
-/* Concatenate three strings, returning a newly malloc'd string. */
-
-char *
-concat (char const *s1, char const *s2, char const *s3)
-{
- char *new = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
- sprintf (new, "%s%s%s", s1, s2, s3);
- return new;
-}
-
-/* Yield a new block of SIZE bytes, initialized to zero. */
-
-void *
-zalloc (size_t size)
-{
- void *p = xmalloc (size);
- memset (p, 0, size);
- return p;
-}
-
-/* Yield the newly malloc'd pathname
- of the file in DIR whose filename is FILE. */
-
-char *
-dir_file_pathname (char const *dir, char const *file)
-{
- char const *base = base_name (dir);
- bool omit_slash = !*base || base[strlen (base) - 1] == '/';
- return concat (dir, "/" + omit_slash, file);
-}
-
-void
-debug_script (struct change *sp)
-{
- fflush (stdout);
-
- for (; sp; sp = sp->link)
- {
- long line0 = sp->line0;
- long line1 = sp->line1;
- long deleted = sp->deleted;
- long inserted = sp->inserted;
- fprintf (stderr, "%3ld %3ld delete %ld insert %ld\n",
- line0, line1, deleted, inserted);
- }
-
- fflush (stderr);
-}