From 93ef69af304a53570b5a794fb8bf837dfe2d5d66 Mon Sep 17 00:00:00 2001 From: tv Date: Fri, 12 Feb 1999 12:45:05 +0000 Subject: [PATCH] Use dist layout for diffutils, and add Texinfo doc. --- gnu/usr.bin/diff/context.c | 468 ---- gnu/usr.bin/diff/diff.c | 1106 -------- gnu/usr.bin/diff/diff.h | 340 --- gnu/usr.bin/diff/diff3.c | 1778 ------------ gnu/usr.bin/diff/dir.c | 216 -- gnu/usr.bin/diff/ed.c | 200 -- gnu/usr.bin/diff/getopt.c | 748 ----- gnu/usr.bin/diff/getopt.h | 129 - gnu/usr.bin/diff/getopt1.c | 180 -- gnu/usr.bin/diff/ifdef.c | 428 --- gnu/usr.bin/diff/io.c | 714 ----- gnu/usr.bin/diff/normal.c | 71 - gnu/usr.bin/diff/regex.c | 5248 ------------------------------------ gnu/usr.bin/diff/regex.h | 490 ---- gnu/usr.bin/diff/sdiff.c | 1180 -------- gnu/usr.bin/diff/side.c | 284 -- gnu/usr.bin/diff/system.h | 267 -- gnu/usr.bin/diff/util.c | 754 ------ gnu/usr.bin/diff/version.c | 5 - gnu/usr.bin/diff3/Makefile | 8 +- gnu/usr.bin/sdiff/Makefile | 8 +- 21 files changed, 10 insertions(+), 14612 deletions(-) delete mode 100644 gnu/usr.bin/diff/context.c delete mode 100644 gnu/usr.bin/diff/diff.c delete mode 100644 gnu/usr.bin/diff/diff.h delete mode 100644 gnu/usr.bin/diff/diff3.c delete mode 100644 gnu/usr.bin/diff/dir.c delete mode 100644 gnu/usr.bin/diff/ed.c delete mode 100644 gnu/usr.bin/diff/getopt.c delete mode 100644 gnu/usr.bin/diff/getopt.h delete mode 100644 gnu/usr.bin/diff/getopt1.c delete mode 100644 gnu/usr.bin/diff/ifdef.c delete mode 100644 gnu/usr.bin/diff/io.c delete mode 100644 gnu/usr.bin/diff/normal.c delete mode 100644 gnu/usr.bin/diff/regex.c delete mode 100644 gnu/usr.bin/diff/regex.h delete mode 100644 gnu/usr.bin/diff/sdiff.c delete mode 100644 gnu/usr.bin/diff/side.c delete mode 100644 gnu/usr.bin/diff/system.h delete mode 100644 gnu/usr.bin/diff/util.c delete mode 100644 gnu/usr.bin/diff/version.c diff --git a/gnu/usr.bin/diff/context.c b/gnu/usr.bin/diff/context.c deleted file mode 100644 index 14f950c52699..000000000000 --- a/gnu/usr.bin/diff/context.c +++ /dev/null @@ -1,468 +0,0 @@ -/* Context-format output routines for GNU DIFF. - Copyright (C) 1988,1989,1991,1992,1993,1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "diff.h" - -static struct change *find_hunk PARAMS((struct change *)); -static void find_function PARAMS((struct file_data const *, int, char const **, size_t *)); -static void mark_ignorable PARAMS((struct change *)); -static void pr_context_hunk PARAMS((struct change *)); -static void pr_unidiff_hunk PARAMS((struct change *)); -static void print_context_label PARAMS ((char const *, struct file_data *, char const *)); -static void print_context_number_range PARAMS((struct file_data const *, int, int)); -static void print_unidiff_number_range PARAMS((struct file_data const *, int, int)); - -/* Last place find_function started searching from. */ -static int find_function_last_search; - -/* The value find_function returned when it started searching there. */ -static int find_function_last_match; - -/* Print a label for a context diff, with a file name and date or a label. */ - -static void -print_context_label (mark, inf, label) - char const *mark; - struct file_data *inf; - char const *label; -{ - if (label) - fprintf (outfile, "%s %s\n", mark, label); - else - { - char const *ct = ctime (&inf->stat.st_mtime); - if (!ct) - ct = "?\n"; - /* See Posix.2 section 4.17.6.1.4 for this format. */ - fprintf (outfile, "%s %s\t%s", mark, inf->name, ct); - } -} - -/* Print a header for a context diff, with the file names and dates. */ - -void -print_context_header (inf, unidiff_flag) - struct file_data inf[]; - int unidiff_flag; -{ - if (unidiff_flag) - { - print_context_label ("---", &inf[0], file_label[0]); - print_context_label ("+++", &inf[1], file_label[1]); - } - else - { - print_context_label ("***", &inf[0], file_label[0]); - print_context_label ("---", &inf[1], file_label[1]); - } -} - -/* Print an edit script in context format. */ - -void -print_context_script (script, unidiff_flag) - struct change *script; - int unidiff_flag; -{ - if (ignore_blank_lines_flag || ignore_regexp_list) - mark_ignorable (script); - else - { - struct change *e; - for (e = script; e; e = e->link) - e->ignore = 0; - } - - find_function_last_search = - files[0].prefix_lines; - find_function_last_match = find_function_last_search - 1; - - if (unidiff_flag) - print_script (script, find_hunk, pr_unidiff_hunk); - else - print_script (script, find_hunk, pr_context_hunk); -} - -/* Print a pair of line numbers with a comma, translated for file FILE. - If the second number is not greater, use the first in place of it. - - Args A and B are internal line numbers. - We print the translated (real) line numbers. */ - -static void -print_context_number_range (file, a, b) - struct file_data const *file; - int a, b; -{ - int 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, "%d,%d", trans_a, trans_b); - else - fprintf (outfile, "%d", trans_b); -} - -/* Print a portion of an edit script in context format. - HUNK is the beginning of the portion to be printed. - The end is marked by a `link' that has been nulled out. - - Prints out lines from both files, and precedes each - line with the appropriate flag-character. */ - -static void -pr_context_hunk (hunk) - struct change *hunk; -{ - int first0, last0, first1, last1, show_from, show_to, i; - struct change *next; - char const *prefix; - char const *function; - size_t function_length; - FILE *out; - - /* Determine range of line numbers involved in each file. */ - - analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to); - - if (!show_from && !show_to) - return; - - /* Include a context's width before and after. */ - - i = - files[0].prefix_lines; - first0 = max (first0 - context, i); - first1 = max (first1 - context, i); - last0 = min (last0 + context, files[0].valid_lines - 1); - last1 = min (last1 + context, files[1].valid_lines - 1); - - /* If desired, find the preceding function definition line in file 0. */ - function = 0; - if (function_regexp_list) - find_function (&files[0], first0, &function, &function_length); - - begin_output (); - out = outfile; - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - fprintf (out, "***************"); - - if (function) - { - fprintf (out, " "); - fwrite (function, 1, min (function_length - 1, 40), out); - } - - fprintf (out, "\n*** "); - print_context_number_range (&files[0], first0, last0); - fprintf (out, " ****\n"); - - if (show_from) - { - next = hunk; - - for (i = first0; i <= last0; i++) - { - /* Skip past changes that apply (in file 0) - only to lines before line I. */ - - while (next && next->line0 + next->deleted <= i) - next = next->link; - - /* Compute the marking for line I. */ - - prefix = " "; - if (next && next->line0 <= i) - /* The change NEXT covers this line. - If lines were inserted here in file 1, this is "changed". - Otherwise it is "deleted". */ - prefix = (next->inserted > 0 ? "!" : "-"); - - print_1_line (prefix, &files[0].linbuf[i]); - } - } - - fprintf (out, "--- "); - print_context_number_range (&files[1], first1, last1); - fprintf (out, " ----\n"); - - if (show_to) - { - next = hunk; - - for (i = first1; i <= last1; i++) - { - /* Skip past changes that apply (in file 1) - only to lines before line I. */ - - while (next && next->line1 + next->inserted <= i) - next = next->link; - - /* Compute the marking for line I. */ - - prefix = " "; - if (next && next->line1 <= i) - /* The change NEXT covers this line. - If lines were deleted here in file 0, this is "changed". - Otherwise it is "inserted". */ - prefix = (next->deleted > 0 ? "!" : "+"); - - print_1_line (prefix, &files[1].linbuf[i]); - } - } -} - -/* Print a pair of line numbers with a comma, translated for file FILE. - If the second number is smaller, use the first in place of it. - If the numbers are equal, print just one number. - - Args A and B are internal line numbers. - We print the translated (real) line numbers. */ - -static void -print_unidiff_number_range (file, a, b) - struct file_data const *file; - int a, b; -{ - int 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, trans_b == trans_a ? "%d" : "%d,0", trans_b); - else - fprintf (outfile, "%d,%d", trans_a, trans_b - trans_a + 1); -} - -/* Print a portion of an edit script in unidiff format. - HUNK is the beginning of the portion to be printed. - The end is marked by a `link' that has been nulled out. - - Prints out lines from both files, and precedes each - line with the appropriate flag-character. */ - -static void -pr_unidiff_hunk (hunk) - struct change *hunk; -{ - int first0, last0, first1, last1, show_from, show_to, i, j, k; - struct change *next; - char const *function; - size_t function_length; - FILE *out; - - /* Determine range of line numbers involved in each file. */ - - analyze_hunk (hunk, &first0, &last0, &first1, &last1, &show_from, &show_to); - - if (!show_from && !show_to) - return; - - /* Include a context's width before and after. */ - - i = - files[0].prefix_lines; - first0 = max (first0 - context, i); - first1 = max (first1 - context, i); - last0 = min (last0 + context, files[0].valid_lines - 1); - last1 = min (last1 + context, files[1].valid_lines - 1); - - /* If desired, find the preceding function definition line in file 0. */ - function = 0; - if (function_regexp_list) - find_function (&files[0], first0, &function, &function_length); - - begin_output (); - out = outfile; - - fprintf (out, "@@ -"); - print_unidiff_number_range (&files[0], first0, last0); - fprintf (out, " +"); - print_unidiff_number_range (&files[1], first1, last1); - fprintf (out, " @@"); - - /* If we looked for and found a function this is part of, - include its name in the header of the diff section. */ - - if (function) - { - putc (' ', out); - fwrite (function, 1, min (function_length - 1, 40), out); - } - putc ('\n', out); - - next = hunk; - i = first0; - j = first1; - - while (i <= last0 || j <= last1) - { - - /* If the line isn't a difference, output the context from file 0. */ - - if (!next || i < next->line0) - { - putc (tab_align_flag ? '\t' : ' ', out); - print_1_line (0, &files[0].linbuf[i++]); - j++; - } - else - { - /* For each difference, first output the deleted part. */ - - k = next->deleted; - while (k--) - { - putc ('-', out); - if (tab_align_flag) - putc ('\t', out); - print_1_line (0, &files[0].linbuf[i++]); - } - - /* Then output the inserted part. */ - - k = next->inserted; - while (k--) - { - putc ('+', out); - if (tab_align_flag) - putc ('\t', out); - print_1_line (0, &files[1].linbuf[j++]); - } - - /* We're done with this hunk, so on to the next! */ - - next = next->link; - } - } -} - -/* Scan a (forward-ordered) edit script for the first place that more than - 2*CONTEXT unchanged lines appear, and return a pointer - to the `struct change' for the last change before those lines. */ - -static struct change * -find_hunk (start) - struct change *start; -{ - struct change *prev; - int top0, top1; - int thresh; - - do - { - /* Compute number of first line in each file beyond this changed. */ - top0 = start->line0 + start->deleted; - top1 = start->line1 + start->inserted; - prev = start; - start = start->link; - /* Threshold distance is 2*CONTEXT between two non-ignorable changes, - but only CONTEXT if one is ignorable. */ - thresh = ((prev->ignore || (start && start->ignore)) - ? context - : 2 * context + 1); - /* It is not supposed to matter which file we check in the end-test. - If it would matter, crash. */ - if (start && start->line0 - top0 != start->line1 - top1) - abort (); - } while (start - /* Keep going if less than THRESH lines - elapse before the affected line. */ - && start->line0 < top0 + thresh); - - return prev; -} - -/* Set the `ignore' flag properly in each change in SCRIPT. - It should be 1 if all the lines inserted or deleted in that change - are ignorable lines. */ - -static void -mark_ignorable (script) - struct change *script; -{ - while (script) - { - struct change *next = script->link; - int first0, last0, first1, last1, deletes, inserts; - - /* Turn this change into a hunk: detach it from the others. */ - script->link = 0; - - /* Determine whether this change is ignorable. */ - analyze_hunk (script, &first0, &last0, &first1, &last1, &deletes, &inserts); - /* Reconnect the chain as before. */ - script->link = next; - - /* If the change is ignorable, mark it. */ - script->ignore = (!deletes && !inserts); - - /* Advance to the following change. */ - script = next; - } -} - -/* Find the last function-header line in FILE prior to line number LINENUM. - This is a line containing a match for the regexp in `function_regexp'. - Store the address of the line text into LINEP and the length of the - line into LENP. - Do not store anything if no function-header is found. */ - -static void -find_function (file, linenum, linep, lenp) - struct file_data const *file; - int linenum; - char const **linep; - size_t *lenp; -{ - int i = linenum; - int last = find_function_last_search; - find_function_last_search = i; - - while (--i >= last) - { - /* See if this line is what we want. */ - struct regexp_list *r; - char const *line = file->linbuf[i]; - size_t len = file->linbuf[i + 1] - line; - - for (r = function_regexp_list; r; r = r->next) - if (0 <= re_search (&r->buf, line, len, 0, len, 0)) - { - *linep = line; - *lenp = len; - find_function_last_match = i; - return; - } - } - /* If we search back to where we started searching the previous time, - find the line we found last time. */ - if (find_function_last_match >= - file->prefix_lines) - { - i = find_function_last_match; - *linep = file->linbuf[i]; - *lenp = file->linbuf[i + 1] - *linep; - return; - } - return; -} diff --git a/gnu/usr.bin/diff/diff.c b/gnu/usr.bin/diff/diff.c deleted file mode 100644 index ab1549be8643..000000000000 --- a/gnu/usr.bin/diff/diff.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* GNU DIFF main routine. - Copyright (C) 1988, 1989, 1992, 1993, 1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* GNU DIFF was written by Mike Haertel, David Hayes, - Richard Stallman, Len Tower, and Paul Eggert. */ - -#define GDIFF_MAIN -#include "diff.h" -#include -#include "getopt.h" -#include "fnmatch.h" - -#ifndef DEFAULT_WIDTH -#define DEFAULT_WIDTH 130 -#endif - -#ifndef GUTTER_WIDTH_MINIMUM -#define GUTTER_WIDTH_MINIMUM 3 -#endif - -static char const *filetype PARAMS((struct stat const *)); -static char *option_list PARAMS((char **, int)); -static int add_exclude_file PARAMS((char const *)); -static int ck_atoi PARAMS((char const *, int *)); -static int compare_files PARAMS((char const *, char const *, char const *, char const *, int)); -static int specify_format PARAMS((char **, char *)); -static void add_exclude PARAMS((char const *)); -static void add_regexp PARAMS((struct regexp_list **, char const *)); -static void specify_style PARAMS((enum output_style)); -static void try_help PARAMS((char const *)); -static void check_stdout PARAMS((void)); -static void usage PARAMS((void)); - -/* Nonzero for -r: if comparing two directories, - compare their common subdirectories recursively. */ - -static int recursive; - -/* For debugging: don't do discard_confusing_lines. */ - -int no_discards; - -#if HAVE_SETMODE -/* I/O mode: nonzero only if using binary input/output. */ -static int binary_I_O; -#endif - -/* Return a string containing the command options with which diff was invoked. - Spaces appear between what were separate ARGV-elements. - There is a space at the beginning but none at the end. - If there were no options, the result is an empty string. - - Arguments: OPTIONVEC, a vector containing separate ARGV-elements, and COUNT, - the length of that vector. */ - -static char * -option_list (optionvec, count) - char **optionvec; /* Was `vector', but that collides on Alliant. */ - int count; -{ - int i; - size_t length = 0; - char *result; - - for (i = 0; i < count; i++) - length += strlen (optionvec[i]) + 1; - - result = xmalloc (length + 1); - result[0] = 0; - - for (i = 0; i < count; i++) - { - strcat (result, " "); - strcat (result, optionvec[i]); - } - - return result; -} - -/* Convert STR to a positive integer, storing the result in *OUT. - If STR is not a valid integer, return -1 (otherwise 0). */ -static int -ck_atoi (str, out) - char const *str; - int *out; -{ - char const *p; - for (p = str; *p; p++) - if (*p < '0' || *p > '9') - return -1; - - *out = atoi (optarg); - return 0; -} - -/* Keep track of excluded file name patterns. */ - -static char const **exclude; -static int exclude_alloc, exclude_count; - -int -excluded_filename (f) - char const *f; -{ - int i; - for (i = 0; i < exclude_count; i++) - if (fnmatch (exclude[i], f, 0) == 0) - return 1; - return 0; -} - -static void -add_exclude (pattern) - char const *pattern; -{ - if (exclude_alloc <= exclude_count) - exclude = (char const **) - (exclude_alloc == 0 - ? xmalloc ((exclude_alloc = 64) * sizeof (*exclude)) - : xrealloc (exclude, (exclude_alloc *= 2) * sizeof (*exclude))); - - exclude[exclude_count++] = pattern; -} - -static int -add_exclude_file (name) - char const *name; -{ - struct file_data f; - char *p, *q, *lim; - - f.name = optarg; - f.desc = (strcmp (optarg, "-") == 0 - ? STDIN_FILENO - : open (optarg, O_RDONLY, 0)); - if (f.desc < 0 || fstat (f.desc, &f.stat) != 0) - return -1; - - sip (&f, 1); - slurp (&f); - - for (p = f.buffer, lim = p + f.buffered_chars; p < lim; p = q) - { - q = (char *) memchr (p, '\n', lim - p); - if (!q) - q = lim; - *q++ = 0; - add_exclude (p); - } - - return close (f.desc); -} - -/* The numbers 129- that appear in the fourth element of some entries - tell the big switch in `main' how to process those options. */ - -static struct option const longopts[] = -{ - {"ignore-blank-lines", 0, 0, 'B'}, - {"context", 2, 0, 'C'}, - {"ifdef", 1, 0, 'D'}, - {"show-function-line", 1, 0, 'F'}, - {"speed-large-files", 0, 0, 'H'}, - {"ignore-matching-lines", 1, 0, 'I'}, - {"label", 1, 0, 'L'}, - {"file-label", 1, 0, 'L'}, /* An alias, no longer recommended */ - {"new-file", 0, 0, 'N'}, - {"entire-new-file", 0, 0, 'N'}, /* An alias, no longer recommended */ - {"unidirectional-new-file", 0, 0, 'P'}, - {"starting-file", 1, 0, 'S'}, - {"initial-tab", 0, 0, 'T'}, - {"width", 1, 0, 'W'}, - {"text", 0, 0, 'a'}, - {"ascii", 0, 0, 'a'}, /* An alias, no longer recommended */ - {"ignore-space-change", 0, 0, 'b'}, - {"minimal", 0, 0, 'd'}, - {"ed", 0, 0, 'e'}, - {"forward-ed", 0, 0, 'f'}, - {"ignore-case", 0, 0, 'i'}, - {"paginate", 0, 0, 'l'}, - {"print", 0, 0, 'l'}, /* An alias, no longer recommended */ - {"rcs", 0, 0, 'n'}, - {"show-c-function", 0, 0, 'p'}, - {"brief", 0, 0, 'q'}, - {"recursive", 0, 0, 'r'}, - {"report-identical-files", 0, 0, 's'}, - {"expand-tabs", 0, 0, 't'}, - {"version", 0, 0, 'v'}, - {"ignore-all-space", 0, 0, 'w'}, - {"exclude", 1, 0, 'x'}, - {"exclude-from", 1, 0, 'X'}, - {"side-by-side", 0, 0, 'y'}, - {"unified", 2, 0, 'U'}, - {"left-column", 0, 0, 129}, - {"suppress-common-lines", 0, 0, 130}, - {"sdiff-merge-assist", 0, 0, 131}, - {"old-line-format", 1, 0, 132}, - {"new-line-format", 1, 0, 133}, - {"unchanged-line-format", 1, 0, 134}, - {"line-format", 1, 0, 135}, - {"old-group-format", 1, 0, 136}, - {"new-group-format", 1, 0, 137}, - {"unchanged-group-format", 1, 0, 138}, - {"changed-group-format", 1, 0, 139}, - {"horizon-lines", 1, 0, 140}, - {"help", 0, 0, 141}, - {"binary", 0, 0, 142}, - {0, 0, 0, 0} -}; - -int -main (argc, argv) - int argc; - char *argv[]; -{ - int val; - int c; - int prev = -1; - int width = DEFAULT_WIDTH; - int show_c_function = 0; - - /* Do our initializations. */ - initialize_main (&argc, &argv); - program_name = argv[0]; - output_style = OUTPUT_NORMAL; - context = -1; - - /* Decode the options. */ - - while ((c = getopt_long (argc, argv, - "0123456789abBcC:dD:efF:hHiI:lL:nNpPqrsS:tTuU:vwW:x:X:y", - longopts, 0)) != EOF) - { - switch (c) - { - /* All digits combine in decimal to specify the context-size. */ - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - if (context == -1) - context = 0; - /* If a context length has already been specified, - more digits allowed only if they follow right after the others. - Reject two separate runs of digits, or digits after -C. */ - else if (prev < '0' || prev > '9') - fatal ("context length specified twice"); - - context = context * 10 + c - '0'; - break; - - case 'a': - /* Treat all files as text files; never treat as binary. */ - always_text_flag = 1; - break; - - case 'b': - /* Ignore changes in amount of white space. */ - ignore_space_change_flag = 1; - ignore_some_changes = 1; - ignore_some_line_changes = 1; - break; - - case 'B': - /* Ignore changes affecting only blank lines. */ - ignore_blank_lines_flag = 1; - ignore_some_changes = 1; - break; - - case 'C': /* +context[=lines] */ - case 'U': /* +unified[=lines] */ - if (optarg) - { - if (context >= 0) - fatal ("context length specified twice"); - - if (ck_atoi (optarg, &context)) - fatal ("invalid context length argument"); - } - - /* Falls through. */ - case 'c': - /* Make context-style output. */ - specify_style (c == 'U' ? OUTPUT_UNIFIED : OUTPUT_CONTEXT); - break; - - case 'd': - /* Don't discard lines. This makes things slower (sometimes much - slower) but will find a guaranteed minimal set of changes. */ - no_discards = 1; - break; - - case 'D': - /* Make merged #ifdef output. */ - specify_style (OUTPUT_IFDEF); - { - int i, err = 0; - static char const C_ifdef_group_formats[] = - "#ifndef %s\n%%<#endif /* not %s */\n%c#ifdef %s\n%%>#endif /* %s */\n%c%%=%c#ifndef %s\n%%<#else /* %s */\n%%>#endif /* %s */\n"; - char *b = xmalloc (sizeof (C_ifdef_group_formats) - + 7 * strlen(optarg) - 14 /* 7*"%s" */ - - 8 /* 5*"%%" + 3*"%c" */); - sprintf (b, C_ifdef_group_formats, - optarg, optarg, 0, - optarg, optarg, 0, 0, - optarg, optarg, optarg); - for (i = 0; i < 4; i++) - { - err |= specify_format (&group_format[i], b); - b += strlen (b) + 1; - } - if (err) - error ("conflicting #ifdef formats", 0, 0); - } - break; - - case 'e': - /* Make output that is a valid `ed' script. */ - specify_style (OUTPUT_ED); - break; - - case 'f': - /* Make output that looks vaguely like an `ed' script - but has changes in the order they appear in the file. */ - specify_style (OUTPUT_FORWARD_ED); - break; - - case 'F': - /* Show, for each set of changes, the previous line that - matches the specified regexp. Currently affects only - context-style output. */ - add_regexp (&function_regexp_list, optarg); - break; - - case 'h': - /* Split the files into chunks of around 1500 lines - for faster processing. Usually does not change the result. - - This currently has no effect. */ - break; - - case 'H': - /* Turn on heuristics that speed processing of large files - with a small density of changes. */ - heuristic = 1; - break; - - case 'i': - /* Ignore changes in case. */ - ignore_case_flag = 1; - ignore_some_changes = 1; - ignore_some_line_changes = 1; - break; - - case 'I': - /* Ignore changes affecting only lines that match the - specified regexp. */ - add_regexp (&ignore_regexp_list, optarg); - ignore_some_changes = 1; - break; - - case 'l': - /* Pass the output through `pr' to paginate it. */ - paginate_flag = 1; -#if !defined(SIGCHLD) && defined(SIGCLD) -#define SIGCHLD SIGCLD -#endif -#ifdef SIGCHLD - /* Pagination requires forking and waiting, and - System V fork+wait does not work if SIGCHLD is ignored. */ - signal (SIGCHLD, SIG_DFL); -#endif - break; - - case 'L': - /* Specify file labels for `-c' output headers. */ - if (!file_label[0]) - file_label[0] = optarg; - else if (!file_label[1]) - file_label[1] = optarg; - else - fatal ("too many file label options"); - break; - - case 'n': - /* Output RCS-style diffs, like `-f' except that each command - specifies the number of lines affected. */ - specify_style (OUTPUT_RCS); - break; - - case 'N': - /* When comparing directories, if a file appears only in one - directory, treat it as present but empty in the other. */ - entire_new_file_flag = 1; - break; - - case 'p': - /* Make context-style output and show name of last C function. */ - show_c_function = 1; - add_regexp (&function_regexp_list, "^[_a-zA-Z$]"); - break; - - case 'P': - /* When comparing directories, if a file appears only in - the second directory of the two, - treat it as present but empty in the other. */ - unidirectional_new_file_flag = 1; - break; - - case 'q': - no_details_flag = 1; - break; - - case 'r': - /* When comparing directories, - recursively compare any subdirectories found. */ - recursive = 1; - break; - - case 's': - /* Print a message if the files are the same. */ - print_file_same_flag = 1; - break; - - case 'S': - /* When comparing directories, start with the specified - file name. This is used for resuming an aborted comparison. */ - dir_start_file = optarg; - break; - - case 't': - /* Expand tabs to spaces in the output so that it preserves - the alignment of the input files. */ - tab_expand_flag = 1; - break; - - case 'T': - /* Use a tab in the output, rather than a space, before the - text of an input line, so as to keep the proper alignment - in the input line without changing the characters in it. */ - tab_align_flag = 1; - break; - - case 'u': - /* Output the context diff in unidiff format. */ - specify_style (OUTPUT_UNIFIED); - break; - - case 'v': - printf ("diff - GNU diffutils version %s\n", version_string); - exit (0); - - case 'w': - /* Ignore horizontal white space when comparing lines. */ - ignore_all_space_flag = 1; - ignore_some_changes = 1; - ignore_some_line_changes = 1; - break; - - case 'x': - add_exclude (optarg); - break; - - case 'X': - if (add_exclude_file (optarg) != 0) - pfatal_with_name (optarg); - break; - - case 'y': - /* Use side-by-side (sdiff-style) columnar output. */ - specify_style (OUTPUT_SDIFF); - break; - - case 'W': - /* Set the line width for OUTPUT_SDIFF. */ - if (ck_atoi (optarg, &width) || width <= 0) - fatal ("column width must be a positive integer"); - break; - - case 129: - sdiff_left_only = 1; - break; - - case 130: - sdiff_skip_common_lines = 1; - break; - - case 131: - /* sdiff-style columns output. */ - specify_style (OUTPUT_SDIFF); - sdiff_help_sdiff = 1; - break; - - case 132: - case 133: - case 134: - specify_style (OUTPUT_IFDEF); - if (specify_format (&line_format[c - 132], optarg) != 0) - error ("conflicting line format", 0, 0); - break; - - case 135: - specify_style (OUTPUT_IFDEF); - { - int i, err = 0; - for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++) - err |= specify_format (&line_format[i], optarg); - if (err) - error ("conflicting line format", 0, 0); - } - break; - - case 136: - case 137: - case 138: - case 139: - specify_style (OUTPUT_IFDEF); - if (specify_format (&group_format[c - 136], optarg) != 0) - error ("conflicting group format", 0, 0); - break; - - case 140: - if (ck_atoi (optarg, &horizon_lines) || horizon_lines < 0) - fatal ("horizon must be a nonnegative integer"); - break; - - case 141: - usage (); - check_stdout (); - exit (0); - - case 142: - /* Use binary I/O when reading and writing data. - On Posix hosts, this has no effect. */ -#if HAVE_SETMODE - binary_I_O = 1; - setmode (STDOUT_FILENO, O_BINARY); -#endif - break; - - default: - try_help (0); - } - prev = c; - } - - if (argc - optind != 2) - try_help (argc - optind < 2 ? "missing operand" : "extra operand"); - - - { - /* - * We maximize first the half line width, and then the gutter width, - * according to the following constraints: - * 1. Two half lines plus a gutter must fit in a line. - * 2. If the half line width is nonzero: - * a. The gutter width is at least GUTTER_WIDTH_MINIMUM. - * b. If tabs are not expanded to spaces, - * a half line plus a gutter is an integral number of tabs, - * so that tabs in the right column line up. - */ - int t = tab_expand_flag ? 1 : TAB_WIDTH; - int off = (width + t + GUTTER_WIDTH_MINIMUM) / (2*t) * t; - sdiff_half_width = max (0, min (off - GUTTER_WIDTH_MINIMUM, width - off)), - sdiff_column2_offset = sdiff_half_width ? off : width; - } - - if (show_c_function && output_style != OUTPUT_UNIFIED) - specify_style (OUTPUT_CONTEXT); - - if (output_style != OUTPUT_CONTEXT && output_style != OUTPUT_UNIFIED) - context = 0; - else if (context == -1) - /* Default amount of context for -c. */ - context = 3; - - if (output_style == OUTPUT_IFDEF) - { - /* Format arrays are char *, not char const *, - because integer formats are temporarily modified. - But it is safe to assign a constant like "%=" to a format array, - since "%=" does not format any integers. */ - int i; - for (i = 0; i < sizeof (line_format) / sizeof (*line_format); i++) - if (!line_format[i]) - line_format[i] = "%l\n"; - if (!group_format[OLD]) - group_format[OLD] - = group_format[UNCHANGED] ? group_format[UNCHANGED] : "%<"; - if (!group_format[NEW]) - group_format[NEW] - = group_format[UNCHANGED] ? group_format[UNCHANGED] : "%>"; - if (!group_format[UNCHANGED]) - group_format[UNCHANGED] = "%="; - if (!group_format[CHANGED]) - group_format[CHANGED] = concat (group_format[OLD], - group_format[NEW], ""); - } - - no_diff_means_no_output = - (output_style == OUTPUT_IFDEF ? - (!*group_format[UNCHANGED] - || (strcmp (group_format[UNCHANGED], "%=") == 0 - && !*line_format[UNCHANGED])) - : output_style == OUTPUT_SDIFF ? sdiff_skip_common_lines : 1); - - switch_string = option_list (argv + 1, optind - 1); - - val = compare_files (0, argv[optind], 0, argv[optind + 1], 0); - - /* Print any messages that were saved up for last. */ - print_message_queue (); - - check_stdout (); - exit (val); - return val; -} - -/* Add the compiled form of regexp PATTERN to REGLIST. */ - -static void -add_regexp (reglist, pattern) - struct regexp_list **reglist; - char const *pattern; -{ - struct regexp_list *r; - char const *m; - - r = (struct regexp_list *) xmalloc (sizeof (*r)); - bzero (r, sizeof (*r)); - r->buf.fastmap = xmalloc (256); - m = re_compile_pattern (pattern, strlen (pattern), &r->buf); - if (m != 0) - error ("%s: %s", pattern, m); - - /* Add to the start of the list, since it's easier than the end. */ - r->next = *reglist; - *reglist = r; -} - -static void -try_help (reason) - char const *reason; -{ - if (reason) - error ("%s", reason, 0); - error ("Try `%s --help' for more information.", program_name, 0); - exit (2); -} - -static void -check_stdout () -{ - if (ferror (stdout) || fclose (stdout) != 0) - fatal ("write error"); -} - -static char const * const option_help[] = { -"-i --ignore-case Consider upper- and lower-case to be the same.", -"-w --ignore-all-space Ignore all white space.", -"-b --ignore-space-change Ignore changes in the amount of white space.", -"-B --ignore-blank-lines Ignore changes whose lines are all blank.", -"-I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.", -#if HAVE_SETMODE -"--binary Read and write data in binary mode.", -#endif -"-a --text Treat all files as text.\n", -"-c -C NUM --context[=NUM] Output NUM (default 2) lines of copied context.", -"-u -U NUM --unified[=NUM] Output NUM (default 2) lines of unified context.", -" -NUM Use NUM context lines.", -" -L LABEL --label LABEL Use LABEL instead of file name.", -" -p --show-c-function Show which C function each change is in.", -" -F RE --show-function-line=RE Show the most recent line matching RE.", -"-q --brief Output only whether files differ.", -"-e --ed Output an ed script.", -"-n --rcs Output an RCS format diff.", -"-y --side-by-side Output in two columns.", -" -w NUM --width=NUM Output at most NUM (default 130) characters per line.", -" --left-column Output only the left column of common lines.", -" --suppress-common-lines Do not output common lines.", -"-DNAME --ifdef=NAME Output merged file to show `#ifdef NAME' diffs.", -"--GTYPE-group-format=GFMT Similar, but format GTYPE input groups with GFMT.", -"--line-format=LFMT Similar, but format all input lines with LFMT.", -"--LTYPE-line-format=LFMT Similar, but format LTYPE input lines with LFMT.", -" LTYPE is `old', `new', or `unchanged'. GTYPE is LTYPE or `changed'.", -" GFMT may contain:", -" %< lines from FILE1", -" %> lines from FILE2", -" %= lines common to FILE1 and FILE2", -" %[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER", -" LETTERs are as follows for new group, lower case for old group:", -" F first line number", -" L last line number", -" N number of lines = L-F+1", -" E F-1", -" M L+1", -" LFMT may contain:", -" %L contents of line", -" %l contents of line, excluding any trailing newline", -" %[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number", -" Either GFMT or LFMT may contain:", -" %% %", -" %c'C' the single character C", -" %c'\\OOO' the character with octal code OOO\n", -"-l --paginate Pass the output through `pr' to paginate it.", -"-t --expand-tabs Expand tabs to spaces in output.", -"-T --initial-tab Make tabs line up by prepending a tab.\n", -"-r --recursive Recursively compare any subdirectories found.", -"-N --new-file Treat absent files as empty.", -"-P --unidirectional-new-file Treat absent first files as empty.", -"-s --report-identical-files Report when two files are the same.", -"-x PAT --exclude=PAT Exclude files that match PAT.", -"-X FILE --exclude-from=FILE Exclude files that match any pattern in FILE.", -"-S FILE --starting-file=FILE Start with FILE when comparing directories.\n", -"--horizon-lines=NUM Keep NUM lines of the common prefix and suffix.", -"-d --minimal Try hard to find a smaller set of changes.", -"-H --speed-large-files Assume large files and many scattered small changes.\n", -"-v --version Output version info.", -"--help Output this help.", -0 -}; - -static void -usage () -{ - char const * const *p; - - printf ("Usage: %s [OPTION]... FILE1 FILE2\n\n", program_name); - for (p = option_help; *p; p++) - printf (" %s\n", *p); - printf ("\nIf FILE1 or FILE2 is `-', read standard input.\n"); -} - -static int -specify_format (var, value) - char **var; - char *value; -{ - int err = *var ? strcmp (*var, value) : 0; - *var = value; - return err; -} - -static void -specify_style (style) - enum output_style style; -{ - if (output_style != OUTPUT_NORMAL - && output_style != style) - error ("conflicting specifications of output style", 0, 0); - output_style = style; -} - -static char const * -filetype (st) - struct stat const *st; -{ - /* See Posix.2 section 4.17.6.1.1 and Table 5-1 for these formats. - To keep diagnostics grammatical, the returned string must start - with a consonant. */ - - if (S_ISREG (st->st_mode)) - { - if (st->st_size == 0) - return "regular empty file"; - /* Posix.2 section 5.14.2 seems to suggest that we must read the file - and guess whether it's C, Fortran, etc., but this is somewhat useless - and doesn't reflect historical practice. We're allowed to guess - wrong, so we don't bother to read the file. */ - return "regular file"; - } - if (S_ISDIR (st->st_mode)) return "directory"; - - /* other Posix.1 file types */ -#ifdef S_ISBLK - if (S_ISBLK (st->st_mode)) return "block special file"; -#endif -#ifdef S_ISCHR - if (S_ISCHR (st->st_mode)) return "character special file"; -#endif -#ifdef S_ISFIFO - if (S_ISFIFO (st->st_mode)) return "fifo"; -#endif - - /* other Posix.1b file types */ -#ifdef S_TYPEISMQ - if (S_TYPEISMQ (st)) return "message queue"; -#endif -#ifdef S_TYPEISSEM - if (S_TYPEISSEM (st)) return "semaphore"; -#endif -#ifdef S_TYPEISSHM - if (S_TYPEISSHM (st)) return "shared memory object"; -#endif - - /* other popular file types */ - /* S_ISLNK is impossible with `fstat' and `stat'. */ -#ifdef S_ISSOCK - if (S_ISSOCK (st->st_mode)) return "socket"; -#endif - - return "weird file"; -} - -/* Compare two files (or dirs) with specified names - DIR0/NAME0 and DIR1/NAME1, at level DEPTH in directory recursion. - (if DIR0 is 0, then the name is just NAME0, etc.) - This is self-contained; it opens the files and closes them. - - Value is 0 if files are the same, 1 if different, - 2 if there is a problem opening them. */ - -static int -compare_files (dir0, name0, dir1, name1, depth) - char const *dir0, *dir1; - char const *name0, *name1; - int depth; -{ - struct file_data inf[2]; - register int i; - int val; - int same_files; - int failed = 0; - char *free0 = 0, *free1 = 0; - - /* If this is directory comparison, perhaps we have a file - that exists only in one of the directories. - If so, just print a message to that effect. */ - - if (! ((name0 != 0 && name1 != 0) - || (unidirectional_new_file_flag && name1 != 0) - || entire_new_file_flag)) - { - char const *name = name0 == 0 ? name1 : name0; - char const *dir = name0 == 0 ? dir1 : dir0; - message ("Only in %s: %s\n", dir, name); - /* Return 1 so that diff_dirs will return 1 ("some files differ"). */ - return 1; - } - - bzero (inf, sizeof (inf)); - - /* Mark any nonexistent file with -1 in the desc field. */ - /* Mark unopened files (e.g. directories) with -2. */ - - inf[0].desc = name0 == 0 ? -1 : -2; - inf[1].desc = name1 == 0 ? -1 : -2; - - /* Now record the full name of each file, including nonexistent ones. */ - - if (name0 == 0) - name0 = name1; - if (name1 == 0) - name1 = name0; - - inf[0].name = dir0 == 0 ? name0 : (free0 = dir_file_pathname (dir0, name0)); - inf[1].name = dir1 == 0 ? name1 : (free1 = dir_file_pathname (dir1, name1)); - - /* Stat the files. Record whether they are directories. */ - - for (i = 0; i <= 1; i++) - { - if (inf[i].desc != -1) - { - int stat_result; - - if (i && filename_cmp (inf[i].name, inf[0].name) == 0) - { - inf[i].stat = inf[0].stat; - stat_result = 0; - } - else if (strcmp (inf[i].name, "-") == 0) - { - inf[i].desc = STDIN_FILENO; - stat_result = fstat (STDIN_FILENO, &inf[i].stat); - if (stat_result == 0 && S_ISREG (inf[i].stat.st_mode)) - { - off_t pos = lseek (STDIN_FILENO, (off_t) 0, SEEK_CUR); - if (pos == -1) - stat_result = -1; - else - { - if (pos <= inf[i].stat.st_size) - inf[i].stat.st_size -= pos; - else - inf[i].stat.st_size = 0; - /* Posix.2 4.17.6.1.4 requires current time for stdin. */ - time (&inf[i].stat.st_mtime); - } - } - } - else - stat_result = stat (inf[i].name, &inf[i].stat); - - if (stat_result != 0) - { - perror_with_name (inf[i].name); - failed = 1; - } - else - { - inf[i].dir_p = S_ISDIR (inf[i].stat.st_mode) && inf[i].desc != 0; - if (inf[1 - i].desc == -1) - { - inf[1 - i].dir_p = inf[i].dir_p; - inf[1 - i].stat.st_mode = inf[i].stat.st_mode; - } - } - } - } - - if (! failed && depth == 0 && inf[0].dir_p != inf[1].dir_p) - { - /* If one is a directory, and it was specified in the command line, - use the file in that dir with the other file's basename. */ - - int fnm_arg = inf[0].dir_p; - int dir_arg = 1 - fnm_arg; - char const *fnm = inf[fnm_arg].name; - char const *dir = inf[dir_arg].name; - char const *p = filename_lastdirchar (fnm); - char const *filename = inf[dir_arg].name - = dir_file_pathname (dir, p ? p + 1 : fnm); - - if (strcmp (fnm, "-") == 0) - fatal ("can't compare - to a directory"); - - if (stat (filename, &inf[dir_arg].stat) != 0) - { - perror_with_name (filename); - failed = 1; - } - else - inf[dir_arg].dir_p = S_ISDIR (inf[dir_arg].stat.st_mode); - } - - if (failed) - { - - /* If either file should exist but does not, return 2. */ - - val = 2; - - } - else if ((same_files = inf[0].desc != -1 && inf[1].desc != -1 - && 0 < same_file (&inf[0].stat, &inf[1].stat)) - && no_diff_means_no_output) - { - /* The two named files are actually the same physical file. - We know they are identical without actually reading them. */ - - val = 0; - } - else if (inf[0].dir_p & inf[1].dir_p) - { - if (output_style == OUTPUT_IFDEF) - fatal ("-D option not supported with directories"); - - /* If both are directories, compare the files in them. */ - - if (depth > 0 && !recursive) - { - /* But don't compare dir contents one level down - unless -r was specified. */ - message ("Common subdirectories: %s and %s\n", - inf[0].name, inf[1].name); - val = 0; - } - else - { - val = diff_dirs (inf, compare_files, depth); - } - - } - else if ((inf[0].dir_p | inf[1].dir_p) - || (depth > 0 - && (! S_ISREG (inf[0].stat.st_mode) - || ! S_ISREG (inf[1].stat.st_mode)))) - { - /* Perhaps we have a subdirectory that exists only in one directory. - If so, just print a message to that effect. */ - - if (inf[0].desc == -1 || inf[1].desc == -1) - { - if ((inf[0].dir_p | inf[1].dir_p) - && recursive - && (entire_new_file_flag - || (unidirectional_new_file_flag && inf[0].desc == -1))) - val = diff_dirs (inf, compare_files, depth); - else - { - char const *dir = (inf[0].desc == -1) ? dir1 : dir0; - /* See Posix.2 section 4.17.6.1.1 for this format. */ - message ("Only in %s: %s\n", dir, name0); - val = 1; - } - } - else - { - /* We have two files that are not to be compared. */ - - /* See Posix.2 section 4.17.6.1.1 for this format. */ - message5 ("File %s is a %s while file %s is a %s\n", - inf[0].name, filetype (&inf[0].stat), - inf[1].name, filetype (&inf[1].stat)); - - /* This is a difference. */ - val = 1; - } - } - else if ((no_details_flag & ~ignore_some_changes) - && inf[0].stat.st_size != inf[1].stat.st_size - && (inf[0].desc == -1 || S_ISREG (inf[0].stat.st_mode)) - && (inf[1].desc == -1 || S_ISREG (inf[1].stat.st_mode))) - { - message ("Files %s and %s differ\n", inf[0].name, inf[1].name); - val = 1; - } - else - { - /* Both exist and neither is a directory. */ - - /* Open the files and record their descriptors. */ - - if (inf[0].desc == -2) - if ((inf[0].desc = open (inf[0].name, O_RDONLY, 0)) < 0) - { - perror_with_name (inf[0].name); - failed = 1; - } - if (inf[1].desc == -2) - if (same_files) - inf[1].desc = inf[0].desc; - else if ((inf[1].desc = open (inf[1].name, O_RDONLY, 0)) < 0) - { - perror_with_name (inf[1].name); - failed = 1; - } - -#if HAVE_SETMODE - if (binary_I_O) - for (i = 0; i <= 1; i++) - if (0 <= inf[i].desc) - setmode (inf[i].desc, O_BINARY); -#endif - - /* Compare the files, if no error was found. */ - - val = failed ? 2 : diff_2_files (inf, depth); - - /* Close the file descriptors. */ - - if (inf[0].desc >= 0 && close (inf[0].desc) != 0) - { - perror_with_name (inf[0].name); - val = 2; - } - if (inf[1].desc >= 0 && inf[0].desc != inf[1].desc - && close (inf[1].desc) != 0) - { - perror_with_name (inf[1].name); - val = 2; - } - } - - /* Now the comparison has been done, if no error prevented it, - and VAL is the value this function will return. */ - - if (val == 0 && !inf[0].dir_p) - { - if (print_file_same_flag) - message ("Files %s and %s are identical\n", - inf[0].name, inf[1].name); - } - else - fflush (stdout); - - if (free0) - free (free0); - if (free1) - free (free1); - - return val; -} diff --git a/gnu/usr.bin/diff/diff.h b/gnu/usr.bin/diff/diff.h deleted file mode 100644 index 66c6940c72bf..000000000000 --- a/gnu/usr.bin/diff/diff.h +++ /dev/null @@ -1,340 +0,0 @@ -/* Shared definitions for GNU DIFF - Copyright (C) 1988, 89, 91, 92, 93 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "system.h" -#include -#include "regex.h" - -#define TAB_WIDTH 8 - -/* Variables for command line options */ - -#ifndef GDIFF_MAIN -#define EXTERN extern -#else -#define EXTERN -#endif - -enum output_style { - /* Default output style. */ - OUTPUT_NORMAL, - /* Output the differences with lines of context before and after (-c). */ - OUTPUT_CONTEXT, - /* Output the differences in a unified context diff format (-u). */ - OUTPUT_UNIFIED, - /* Output the differences as commands suitable for `ed' (-e). */ - OUTPUT_ED, - /* Output the diff as a forward ed script (-f). */ - OUTPUT_FORWARD_ED, - /* Like -f, but output a count of changed lines in each "command" (-n). */ - OUTPUT_RCS, - /* Output merged #ifdef'd file (-D). */ - OUTPUT_IFDEF, - /* Output sdiff style (-y). */ - OUTPUT_SDIFF -}; - -/* True for output styles that are robust, - i.e. can handle a file that ends in a non-newline. */ -#define ROBUST_OUTPUT_STYLE(S) ((S) != OUTPUT_ED && (S) != OUTPUT_FORWARD_ED) - -EXTERN enum output_style output_style; - -/* Nonzero if output cannot be generated for identical files. */ -EXTERN int no_diff_means_no_output; - -/* Number of lines of context to show in each set of diffs. - This is zero when context is not to be shown. */ -EXTERN int context; - -/* Consider all files as text files (-a). - Don't interpret codes over 0177 as implying a "binary file". */ -EXTERN int always_text_flag; - -/* Number of lines to keep in identical prefix and suffix. */ -EXTERN int horizon_lines; - -/* Ignore changes in horizontal white space (-b). */ -EXTERN int ignore_space_change_flag; - -/* Ignore all horizontal white space (-w). */ -EXTERN int ignore_all_space_flag; - -/* Ignore changes that affect only blank lines (-B). */ -EXTERN int ignore_blank_lines_flag; - -/* 1 if lines may match even if their contents do not match exactly. - This depends on various options. */ -EXTERN int ignore_some_line_changes; - -/* 1 if files may match even if their contents are not byte-for-byte identical. - This depends on various options. */ -EXTERN int ignore_some_changes; - -/* Ignore differences in case of letters (-i). */ -EXTERN int ignore_case_flag; - -/* File labels for `-c' output headers (-L). */ -EXTERN char *file_label[2]; - -struct regexp_list -{ - struct re_pattern_buffer buf; - struct regexp_list *next; -}; - -/* Regexp to identify function-header lines (-F). */ -EXTERN struct regexp_list *function_regexp_list; - -/* Ignore changes that affect only lines matching this regexp (-I). */ -EXTERN struct regexp_list *ignore_regexp_list; - -/* Say only whether files differ, not how (-q). */ -EXTERN int no_details_flag; - -/* Report files compared that match (-s). - Normally nothing is output when that happens. */ -EXTERN int print_file_same_flag; - -/* Output the differences with exactly 8 columns added to each line - so that any tabs in the text line up properly (-T). */ -EXTERN int tab_align_flag; - -/* Expand tabs in the output so the text lines up properly - despite the characters added to the front of each line (-t). */ -EXTERN int tab_expand_flag; - -/* In directory comparison, specify file to start with (-S). - All file names less than this name are ignored. */ -EXTERN char *dir_start_file; - -/* If a file is new (appears in only one dir) - include its entire contents (-N). - Then `patch' would create the file with appropriate contents. */ -EXTERN int entire_new_file_flag; - -/* If a file is new (appears in only the second dir) - include its entire contents (-P). - Then `patch' would create the file with appropriate contents. */ -EXTERN int unidirectional_new_file_flag; - -/* Pipe each file's output through pr (-l). */ -EXTERN int paginate_flag; - -enum line_class { - /* Lines taken from just the first file. */ - OLD, - /* Lines taken from just the second file. */ - NEW, - /* Lines common to both files. */ - UNCHANGED, - /* A hunk containing both old and new lines (line groups only). */ - CHANGED -}; - -/* Line group formats for old, new, unchanged, and changed groups. */ -EXTERN char *group_format[CHANGED + 1]; - -/* Line formats for old, new, and unchanged lines. */ -EXTERN char *line_format[UNCHANGED + 1]; - -/* If using OUTPUT_SDIFF print extra information to help the sdiff filter. */ -EXTERN int sdiff_help_sdiff; - -/* Tell OUTPUT_SDIFF to show only the left version of common lines. */ -EXTERN int sdiff_left_only; - -/* Tell OUTPUT_SDIFF to not show common lines. */ -EXTERN int sdiff_skip_common_lines; - -/* The half line width and column 2 offset for OUTPUT_SDIFF. */ -EXTERN unsigned sdiff_half_width; -EXTERN unsigned sdiff_column2_offset; - -/* String containing all the command options diff received, - with spaces between and at the beginning but none at the end. - If there were no options given, this string is empty. */ -EXTERN char * switch_string; - -/* Nonzero means use heuristics for better speed. */ -EXTERN int heuristic; - -/* Name of program the user invoked (for error messages). */ -EXTERN char *program_name; - -/* The result of comparison is an "edit script": a chain of `struct change'. - Each `struct change' represents one place where some lines are deleted - and some are inserted. - - LINE0 and LINE1 are the first affected lines in the two files (origin 0). - DELETED is the number of lines deleted here from file 0. - INSERTED is the number of lines inserted here in file 1. - - If DELETED is 0 then LINE0 is the number of the line before - which the insertion was done; vice versa for INSERTED and LINE1. */ - -struct change -{ - struct change *link; /* Previous or next edit command */ - int inserted; /* # lines of file 1 changed here. */ - int deleted; /* # lines of file 0 changed here. */ - int line0; /* Line number of 1st deleted line. */ - int line1; /* Line number of 1st inserted line. */ - char ignore; /* Flag used in context.c */ -}; - -/* Structures that describe the input files. */ - -/* Data on one input file being compared. */ - -struct file_data { - int desc; /* File descriptor */ - char const *name; /* File name */ - struct stat stat; /* File status from fstat() */ - int dir_p; /* nonzero if file is a directory */ - - /* Buffer in which text of file is read. */ - char * buffer; - /* Allocated size of buffer. */ - size_t bufsize; - /* Number of valid characters now in the buffer. */ - size_t buffered_chars; - - /* Array of pointers to lines in the file. */ - char const **linbuf; - - /* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines. - linebuf[linbuf_base ... buffered_lines - 1] are possibly differing. - linebuf[linbuf_base ... valid_lines - 1] contain valid data. - linebuf[linbuf_base ... alloc_lines - 1] are allocated. */ - int linbuf_base, buffered_lines, valid_lines, alloc_lines; - - /* Pointer to end of prefix of this file to ignore when hashing. */ - char const *prefix_end; - - /* Count of lines in the prefix. - There are this many lines in the file before linbuf[0]. */ - int prefix_lines; - - /* Pointer to start of suffix of this file to ignore when hashing. */ - char const *suffix_begin; - - /* Vector, indexed by line number, containing an equivalence code for - each line. It is this vector that is actually compared with that - of another file to generate differences. */ - int *equivs; - - /* Vector, like the previous one except that - the elements for discarded lines have been squeezed out. */ - int *undiscarded; - - /* Vector mapping virtual line numbers (not counting discarded lines) - to real ones (counting those lines). Both are origin-0. */ - int *realindexes; - - /* Total number of nondiscarded lines. */ - int nondiscarded_lines; - - /* Vector, indexed by real origin-0 line number, - containing 1 for a line that is an insertion or a deletion. - The results of comparison are stored here. */ - char *changed_flag; - - /* 1 if file ends in a line with no final newline. */ - int missing_newline; - - /* 1 more than the maximum equivalence value used for this or its - sibling file. */ - int equiv_max; -}; - -/* Describe the two files currently being compared. */ - -EXTERN struct file_data files[2]; - -/* Stdio stream to output diffs to. */ - -EXTERN FILE *outfile; - -/* Declare various functions. */ - -/* analyze.c */ -int diff_2_files PARAMS((struct file_data[], int)); - -/* context.c */ -void print_context_header PARAMS((struct file_data[], int)); -void print_context_script PARAMS((struct change *, int)); - -/* diff.c */ -int excluded_filename PARAMS((char const *)); - -/* dir.c */ -int diff_dirs PARAMS((struct file_data const[], int (*) PARAMS((char const *, char const *, char const *, char const *, int)), int)); - -/* ed.c */ -void print_ed_script PARAMS((struct change *)); -void pr_forward_ed_script PARAMS((struct change *)); - -/* ifdef.c */ -void print_ifdef_script PARAMS((struct change *)); - -/* io.c */ -int read_files PARAMS((struct file_data[], int)); -int sip PARAMS((struct file_data *, int)); -void slurp PARAMS((struct file_data *)); - -/* normal.c */ -void print_normal_script PARAMS((struct change *)); - -/* rcs.c */ -void print_rcs_script PARAMS((struct change *)); - -/* side.c */ -void print_sdiff_script PARAMS((struct change *)); - -/* util.c */ -VOID *xmalloc PARAMS((size_t)); -VOID *xrealloc PARAMS((VOID *, size_t)); -char *concat PARAMS((char const *, char const *, char const *)); -char *dir_file_pathname PARAMS((char const *, char const *)); -int change_letter PARAMS((int, int)); -int line_cmp PARAMS((char const *, char const *)); -int translate_line_number PARAMS((struct file_data const *, int)); -struct change *find_change PARAMS((struct change *)); -struct change *find_reverse_change PARAMS((struct change *)); -void analyze_hunk PARAMS((struct change *, int *, int *, int *, int *, int *, int *)); -void begin_output PARAMS((void)); -void debug_script PARAMS((struct change *)); -void error PARAMS((char const *, char const *, char const *)); -void fatal PARAMS((char const *)); -void finish_output PARAMS((void)); -void message PARAMS((char const *, char const *, char const *)); -void message5 PARAMS((char const *, char const *, char const *, char const *, char const *)); -void output_1_line PARAMS((char const *, char const *, char const *, char const *)); -void perror_with_name PARAMS((char const *)); -void pfatal_with_name PARAMS((char const *)); -void print_1_line PARAMS((char const *, char const * const *)); -void print_message_queue PARAMS((void)); -void print_number_range PARAMS((int, struct file_data *, int, int)); -void print_script PARAMS((struct change *, struct change * (*) PARAMS((struct change *)), void (*) PARAMS((struct change *)))); -void setup_output PARAMS((char const *, char const *, int)); -void translate_range PARAMS((struct file_data const *, int, int, int *, int *)); - -/* version.c */ -extern char const version_string[]; diff --git a/gnu/usr.bin/diff/diff3.c b/gnu/usr.bin/diff/diff3.c deleted file mode 100644 index 5d94ab866dbc..000000000000 --- a/gnu/usr.bin/diff/diff3.c +++ /dev/null @@ -1,1778 +0,0 @@ -/* Three way file comparison program (diff3) for Project GNU. - Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc. - - This program 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. - - This program 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; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* Written by Randy Smith */ - -#include "system.h" -#include -#include -#include "getopt.h" - -extern char const version_string[]; - -/* - * Internal data structures and macros for the diff3 program; includes - * data structures for both diff3 diffs and normal diffs. - */ - -/* Different files within a three way diff. */ -#define FILE0 0 -#define FILE1 1 -#define FILE2 2 - -/* - * A three way diff is built from two two-way diffs; the file which - * the two two-way diffs share is: - */ -#define FILEC FILE2 - -/* - * Different files within a two way diff. - * FC is the common file, FO the other file. - */ -#define FO 0 -#define FC 1 - -/* The ranges are indexed by */ -#define START 0 -#define END 1 - -enum diff_type { - ERROR, /* Should not be used */ - ADD, /* Two way diff add */ - CHANGE, /* Two way diff change */ - DELETE, /* Two way diff delete */ - DIFF_ALL, /* All three are different */ - DIFF_1ST, /* Only the first is different */ - DIFF_2ND, /* Only the second */ - DIFF_3RD /* Only the third */ -}; - -/* Two way diff */ -struct diff_block { - int ranges[2][2]; /* Ranges are inclusive */ - char **lines[2]; /* The actual lines (may contain nulls) */ - size_t *lengths[2]; /* Line lengths (including newlines, if any) */ - struct diff_block *next; -}; - -/* Three way diff */ - -struct diff3_block { - enum diff_type correspond; /* Type of diff */ - int ranges[3][2]; /* Ranges are inclusive */ - char **lines[3]; /* The actual lines (may contain nulls) */ - size_t *lengths[3]; /* Line lengths (including newlines, if any) */ - struct diff3_block *next; -}; - -/* - * Access the ranges on a diff block. - */ -#define D_LOWLINE(diff, filenum) \ - ((diff)->ranges[filenum][START]) -#define D_HIGHLINE(diff, filenum) \ - ((diff)->ranges[filenum][END]) -#define D_NUMLINES(diff, filenum) \ - (D_HIGHLINE (diff, filenum) - D_LOWLINE (diff, filenum) + 1) - -/* - * Access the line numbers in a file in a diff by relative line - * numbers (i.e. line number within the diff itself). Note that these - * are lvalues and can be used for assignment. - */ -#define D_RELNUM(diff, filenum, linenum) \ - ((diff)->lines[filenum][linenum]) -#define D_RELLEN(diff, filenum, linenum) \ - ((diff)->lengths[filenum][linenum]) - -/* - * And get at them directly, when that should be necessary. - */ -#define D_LINEARRAY(diff, filenum) \ - ((diff)->lines[filenum]) -#define D_LENARRAY(diff, filenum) \ - ((diff)->lengths[filenum]) - -/* - * Next block. - */ -#define D_NEXT(diff) ((diff)->next) - -/* - * Access the type of a diff3 block. - */ -#define D3_TYPE(diff) ((diff)->correspond) - -/* - * Line mappings based on diffs. The first maps off the top of the - * diff, the second off of the bottom. - */ -#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \ - ((lineno) \ - - D_HIGHLINE ((diff), (fromfile)) \ - + D_HIGHLINE ((diff), (tofile))) - -#define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \ - ((lineno) \ - - D_LOWLINE ((diff), (fromfile)) \ - + D_LOWLINE ((diff), (tofile))) - -/* - * General memory allocation function. - */ -#define ALLOCATE(number, type) \ - (type *) xmalloc ((number) * sizeof (type)) - -/* Options variables for flags set on command line. */ - -/* If nonzero, treat all files as text files, never as binary. */ -static int always_text; - -/* If nonzero, write out an ed script instead of the standard diff3 format. */ -static int edscript; - -/* If nonzero, in the case of overlapping diffs (type DIFF_ALL), - preserve the lines which would normally be deleted from - file 1 with a special flagging mechanism. */ -static int flagging; - -/* Number of lines to keep in identical prefix and suffix. */ -static int horizon_lines = 10; - -/* Use a tab to align output lines (-T). */ -static int tab_align_flag; - -/* If nonzero, do not output information for overlapping diffs. */ -static int simple_only; - -/* If nonzero, do not output information for non-overlapping diffs. */ -static int overlap_only; - -/* If nonzero, show information for DIFF_2ND diffs. */ -static int show_2nd; - -/* If nonzero, include `:wq' at the end of the script - to write out the file being edited. */ -static int finalwrite; - -/* If nonzero, output a merged file. */ -static int merge; - -static char *program_name; - -static VOID *xmalloc PARAMS((size_t)); -static VOID *xrealloc PARAMS((VOID *, size_t)); - -static char *read_diff PARAMS((char const *, char const *, char **)); -static char *scan_diff_line PARAMS((char *, char **, size_t *, char *, int)); -static enum diff_type process_diff_control PARAMS((char **, struct diff_block *)); -static int compare_line_list PARAMS((char * const[], size_t const[], char * const[], size_t const[], int)); -static int copy_stringlist PARAMS((char * const[], size_t const[], char *[], size_t[], int)); -static int dotlines PARAMS((FILE *, struct diff3_block *, int)); -static int output_diff3_edscript PARAMS((FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); -static int output_diff3_merge PARAMS((FILE *, FILE *, struct diff3_block *, int const[3], int const[3], char const *, char const *, char const *)); -static size_t myread PARAMS((int, char *, size_t)); -static struct diff3_block *create_diff3_block PARAMS((int, int, int, int, int, int)); -static struct diff3_block *make_3way_diff PARAMS((struct diff_block *, struct diff_block *)); -static struct diff3_block *reverse_diff3_blocklist PARAMS((struct diff3_block *)); -static struct diff3_block *using_to_diff3_block PARAMS((struct diff_block *[2], struct diff_block *[2], int, int, struct diff3_block const *)); -static struct diff_block *process_diff PARAMS((char const *, char const *, struct diff_block **)); -static void check_stdout PARAMS((void)); -static void fatal PARAMS((char const *)); -static void output_diff3 PARAMS((FILE *, struct diff3_block *, int const[3], int const[3])); -static void perror_with_exit PARAMS((char const *)); -static void try_help PARAMS((char const *)); -static void undotlines PARAMS((FILE *, int, int, int)); -static void usage PARAMS((void)); - -static char const diff_program[] = DIFF_PROGRAM; - -static struct option const longopts[] = -{ - {"text", 0, 0, 'a'}, - {"show-all", 0, 0, 'A'}, - {"ed", 0, 0, 'e'}, - {"show-overlap", 0, 0, 'E'}, - {"label", 1, 0, 'L'}, - {"merge", 0, 0, 'm'}, - {"initial-tab", 0, 0, 'T'}, - {"overlap-only", 0, 0, 'x'}, - {"easy-only", 0, 0, '3'}, - {"version", 0, 0, 'v'}, - {"help", 0, 0, 129}, - {0, 0, 0, 0} -}; - -/* - * Main program. Calls diff twice on two pairs of input files, - * combines the two diffs, and outputs them. - */ -int -main (argc, argv) - int argc; - char **argv; -{ - int c, i; - int mapping[3]; - int rev_mapping[3]; - int incompat = 0; - int conflicts_found; - struct diff_block *thread0, *thread1, *last_block; - struct diff3_block *diff3; - int tag_count = 0; - char *tag_strings[3]; - char *commonname; - char **file; - struct stat statb; - - initialize_main (&argc, &argv); - program_name = argv[0]; - - while ((c = getopt_long (argc, argv, "aeimvx3AEL:TX", longopts, 0)) != EOF) - { - switch (c) - { - case 'a': - always_text = 1; - break; - case 'A': - show_2nd = 1; - flagging = 1; - incompat++; - break; - case 'x': - overlap_only = 1; - incompat++; - break; - case '3': - simple_only = 1; - incompat++; - break; - case 'i': - finalwrite = 1; - break; - case 'm': - merge = 1; - break; - case 'X': - overlap_only = 1; - /* Falls through */ - case 'E': - flagging = 1; - /* Falls through */ - case 'e': - incompat++; - break; - case 'T': - tab_align_flag = 1; - break; - case 'v': - printf ("diff3 - GNU diffutils version %s\n", version_string); - exit (0); - case 129: - usage (); - check_stdout (); - exit (0); - case 'L': - /* Handle up to three -L options. */ - if (tag_count < 3) - { - tag_strings[tag_count++] = optarg; - break; - } - try_help ("Too many labels were given. The limit is 3."); - default: - try_help (0); - } - } - - edscript = incompat & ~merge; /* -AeExX3 without -m implies ed script. */ - show_2nd |= ~incompat & merge; /* -m without -AeExX3 implies -A. */ - flagging |= ~incompat & merge; - - if (incompat > 1 /* Ensure at most one of -AeExX3. */ - || finalwrite & merge /* -i -m would rewrite input file. */ - || (tag_count && ! flagging)) /* -L requires one of -AEX. */ - try_help ("incompatible options"); - - if (argc - optind != 3) - try_help (argc - optind < 3 ? "missing operand" : "extra operand"); - - file = &argv[optind]; - - for (i = tag_count; i < 3; i++) - tag_strings[i] = file[i]; - - /* Always compare file1 to file2, even if file2 is "-". - This is needed for -mAeExX3. Using the file0 as - the common file would produce wrong results, because if the - file0-file1 diffs didn't line up with the file0-file2 diffs - (which is entirely possible since we don't use diff's -n option), - diff3 might report phantom changes from file1 to file2. */ - - if (strcmp (file[2], "-") == 0) - { - /* Sigh. We've got standard input as the last arg. We can't - call diff twice on stdin. Use the middle arg as the common - file instead. */ - if (strcmp (file[0], "-") == 0 || strcmp (file[1], "-") == 0) - fatal ("`-' specified for more than one input file"); - mapping[0] = 0; - mapping[1] = 2; - mapping[2] = 1; - } - else - { - /* Normal, what you'd expect */ - mapping[0] = 0; - mapping[1] = 1; - mapping[2] = 2; - } - - for (i = 0; i < 3; i++) - rev_mapping[mapping[i]] = i; - - for (i = 0; i < 3; i++) - if (strcmp (file[i], "-") != 0) - { - if (stat (file[i], &statb) < 0) - perror_with_exit (file[i]); - else if (S_ISDIR(statb.st_mode)) - { - fprintf (stderr, "%s: %s: Is a directory\n", - program_name, file[i]); - exit (2); - } - } - -#if !defined(SIGCHLD) && defined(SIGCLD) -#define SIGCHLD SIGCLD -#endif -#ifdef SIGCHLD - /* System V fork+wait does not work if SIGCHLD is ignored. */ - signal (SIGCHLD, SIG_DFL); -#endif - - commonname = file[rev_mapping[FILEC]]; - thread1 = process_diff (file[rev_mapping[FILE1]], commonname, &last_block); - if (thread1) - for (i = 0; i < 2; i++) - { - horizon_lines = max (horizon_lines, D_NUMLINES (thread1, i)); - horizon_lines = max (horizon_lines, D_NUMLINES (last_block, i)); - } - thread0 = process_diff (file[rev_mapping[FILE0]], commonname, &last_block); - diff3 = make_3way_diff (thread0, thread1); - if (edscript) - conflicts_found - = output_diff3_edscript (stdout, diff3, mapping, rev_mapping, - tag_strings[0], tag_strings[1], tag_strings[2]); - else if (merge) - { - if (! freopen (file[rev_mapping[FILE0]], "r", stdin)) - perror_with_exit (file[rev_mapping[FILE0]]); - conflicts_found - = output_diff3_merge (stdin, stdout, diff3, mapping, rev_mapping, - tag_strings[0], tag_strings[1], tag_strings[2]); - if (ferror (stdin)) - fatal ("read error"); - } - else - { - output_diff3 (stdout, diff3, mapping, rev_mapping); - conflicts_found = 0; - } - - check_stdout (); - exit (conflicts_found); - return conflicts_found; -} - -static void -try_help (reason) - char const *reason; -{ - if (reason) - fprintf (stderr, "%s: %s\n", program_name, reason); - fprintf (stderr, "%s: Try `%s --help' for more information.\n", - program_name, program_name); - exit (2); -} - -static void -check_stdout () -{ - if (ferror (stdout) || fclose (stdout) != 0) - fatal ("write error"); -} - -/* - * Explain, patiently and kindly, how to use this program. - */ -static void -usage () -{ - printf ("Usage: %s [OPTION]... MYFILE OLDFILE YOURFILE\n\n", program_name); - - printf ("%s", "\ - -e --ed Output unmerged changes from OLDFILE to YOURFILE into MYFILE.\n\ - -E --show-overlap Output unmerged changes, bracketing conflicts.\n\ - -A --show-all Output all changes, bracketing conflicts.\n\ - -x --overlap-only Output overlapping changes.\n\ - -X Output overlapping changes, bracketing them.\n\ - -3 --easy-only Output unmerged nonoverlapping changes.\n\n"); - printf ("%s", "\ - -m --merge Output merged file instead of ed script (default -A).\n\ - -L LABEL --label=LABEL Use LABEL instead of file name.\n\ - -i Append `w' and `q' commands to ed scripts.\n\ - -a --text Treat all files as text.\n\ - -T --initial-tab Make tabs line up by prepending a tab.\n\n"); - printf ("%s", "\ - -v --version Output version info.\n\ - --help Output this help.\n\n"); - printf ("If a FILE is `-', read standard input.\n"); -} - -/* - * Routines that combine the two diffs together into one. The - * algorithm used follows: - * - * File2 is shared in common between the two diffs. - * Diff02 is the diff between 0 and 2. - * Diff12 is the diff between 1 and 2. - * - * 1) Find the range for the first block in File2. - * a) Take the lowest of the two ranges (in File2) in the two - * current blocks (one from each diff) as being the low - * water mark. Assign the upper end of this block as - * being the high water mark and move the current block up - * one. Mark the block just moved over as to be used. - * b) Check the next block in the diff that the high water - * mark is *not* from. - * - * *If* the high water mark is above - * the low end of the range in that block, - * - * mark that block as to be used and move the current - * block up. Set the high water mark to the max of - * the high end of this block and the current. Repeat b. - * - * 2) Find the corresponding ranges in File0 (from the blocks - * in diff02; line per line outside of diffs) and in File1. - * Create a diff3_block, reserving space as indicated by the ranges. - * - * 3) Copy all of the pointers for file2 in. At least for now, - * do memcmp's between corresponding strings in the two diffs. - * - * 4) Copy all of the pointers for file0 and 1 in. Get what you - * need from file2 (when there isn't a diff block, it's - * identical to file2 within the range between diff blocks). - * - * 5) If the diff blocks you used came from only one of the two - * strings of diffs, then that file (i.e. the one other than - * the common file in that diff) is the odd person out. If you used - * diff blocks from both sets, check to see if files 0 and 1 match: - * - * Same number of lines? If so, do a set of memcmp's (if a - * memcmp matches; copy the pointer over; it'll be easier later - * if you have to do any compares). If they match, 0 & 1 are - * the same. If not, all three different. - * - * Then you do it again, until you run out of blocks. - * - */ - -/* - * This routine makes a three way diff (chain of diff3_block's) from two - * two way diffs (chains of diff_block's). It is assumed that each of - * the two diffs passed are onto the same file (i.e. that each of the - * diffs were made "to" the same file). The three way diff pointer - * returned will have numbering FILE0--the other file in diff02, - * FILE1--the other file in diff12, and FILEC--the common file. - */ -static struct diff3_block * -make_3way_diff (thread0, thread1) - struct diff_block *thread0, *thread1; -{ -/* - * This routine works on the two diffs passed to it as threads. - * Thread number 0 is diff02, thread number 1 is diff12. The USING - * array is set to the base of the list of blocks to be used to - * construct each block of the three way diff; if no blocks from a - * particular thread are to be used, that element of the using array - * is set to 0. The elements LAST_USING array are set to the last - * elements on each of the using lists. - * - * The HIGH_WATER_MARK is set to the highest line number in the common file - * described in any of the diffs in either of the USING lists. The - * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK - * and BASE_WATER_THREAD describe the lowest line number in the common file - * described in any of the diffs in either of the USING lists. The - * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was - * taken. - * - * The HIGH_WATER_DIFF should always be equal to LAST_USING - * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for - * higher water, and should always be equal to - * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread - * in which the OTHER_DIFF is, and hence should always be equal to - * HIGH_WATER_THREAD ^ 0x1. - * - * The variable LAST_DIFF is kept set to the last diff block produced - * by this routine, for line correspondence purposes between that diff - * and the one currently being worked on. It is initialized to - * ZERO_DIFF before any blocks have been created. - */ - - struct diff_block - *using[2], - *last_using[2], - *current[2]; - - int - high_water_mark; - - int - high_water_thread, - base_water_thread, - other_thread; - - struct diff_block - *high_water_diff, - *other_diff; - - struct diff3_block - *result, - *tmpblock, - **result_end; - - struct diff3_block const *last_diff3; - - static struct diff3_block const zero_diff3; - - /* Initialization */ - result = 0; - result_end = &result; - current[0] = thread0; current[1] = thread1; - last_diff3 = &zero_diff3; - - /* Sniff up the threads until we reach the end */ - - while (current[0] || current[1]) - { - using[0] = using[1] = last_using[0] = last_using[1] = 0; - - /* Setup low and high water threads, diffs, and marks. */ - if (!current[0]) - base_water_thread = 1; - else if (!current[1]) - base_water_thread = 0; - else - base_water_thread = - (D_LOWLINE (current[0], FC) > D_LOWLINE (current[1], FC)); - - high_water_thread = base_water_thread; - - high_water_diff = current[high_water_thread]; - -#if 0 - /* low and high waters start off same diff */ - base_water_mark = D_LOWLINE (high_water_diff, FC); -#endif - - high_water_mark = D_HIGHLINE (high_water_diff, FC); - - /* Make the diff you just got info from into the using class */ - using[high_water_thread] - = last_using[high_water_thread] - = high_water_diff; - current[high_water_thread] = high_water_diff->next; - last_using[high_water_thread]->next = 0; - - /* And mark the other diff */ - other_thread = high_water_thread ^ 0x1; - other_diff = current[other_thread]; - - /* Shuffle up the ladder, checking the other diff to see if it - needs to be incorporated. */ - while (other_diff - && D_LOWLINE (other_diff, FC) <= high_water_mark + 1) - { - - /* Incorporate this diff into the using list. Note that - this doesn't take it off the current list */ - if (using[other_thread]) - last_using[other_thread]->next = other_diff; - else - using[other_thread] = other_diff; - last_using[other_thread] = other_diff; - - /* Take it off the current list. Note that this following - code assumes that other_diff enters it equal to - current[high_water_thread ^ 0x1] */ - current[other_thread] = current[other_thread]->next; - other_diff->next = 0; - - /* Set the high_water stuff - If this comparison is equal, then this is the last pass - through this loop; since diff blocks within a given - thread cannot overlap, the high_water_mark will be - *below* the range_start of either of the next diffs. */ - - if (high_water_mark < D_HIGHLINE (other_diff, FC)) - { - high_water_thread ^= 1; - high_water_diff = other_diff; - high_water_mark = D_HIGHLINE (other_diff, FC); - } - - /* Set the other diff */ - other_thread = high_water_thread ^ 0x1; - other_diff = current[other_thread]; - } - - /* The using lists contain a list of all of the blocks to be - included in this diff3_block. Create it. */ - - tmpblock = using_to_diff3_block (using, last_using, - base_water_thread, high_water_thread, - last_diff3); - - if (!tmpblock) - fatal ("internal error: screwup in format of diff blocks"); - - /* Put it on the list. */ - *result_end = tmpblock; - result_end = &tmpblock->next; - - /* Set up corresponding lines correctly. */ - last_diff3 = tmpblock; - } - return result; -} - -/* - * using_to_diff3_block: - * This routine takes two lists of blocks (from two separate diff - * threads) and puts them together into one diff3 block. - * It then returns a pointer to this diff3 block or 0 for failure. - * - * All arguments besides using are for the convenience of the routine; - * they could be derived from the using array. - * LAST_USING is a pair of pointers to the last blocks in the using - * structure. - * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest - * and highest line numbers for File0. - * last_diff3 contains the last diff produced in the calling routine. - * This is used for lines mappings which would still be identical to - * the state that diff ended in. - * - * A distinction should be made in this routine between the two diffs - * that are part of a normal two diff block, and the three diffs that - * are part of a diff3_block. - */ -static struct diff3_block * -using_to_diff3_block (using, last_using, low_thread, high_thread, last_diff3) - struct diff_block - *using[2], - *last_using[2]; - int low_thread, high_thread; - struct diff3_block const *last_diff3; -{ - int low[2], high[2]; - struct diff3_block *result; - struct diff_block *ptr; - int d, i; - - /* Find the range in the common file. */ - int lowc = D_LOWLINE (using[low_thread], FC); - int highc = D_HIGHLINE (last_using[high_thread], FC); - - /* Find the ranges in the other files. - If using[d] is null, that means that the file to which that diff - refers is equivalent to the common file over this range. */ - - for (d = 0; d < 2; d++) - if (using[d]) - { - low[d] = D_LOW_MAPLINE (using[d], FC, FO, lowc); - high[d] = D_HIGH_MAPLINE (last_using[d], FC, FO, highc); - } - else - { - low[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, lowc); - high[d] = D_HIGH_MAPLINE (last_diff3, FILEC, FILE0 + d, highc); - } - - /* Create a block with the appropriate sizes */ - result = create_diff3_block (low[0], high[0], low[1], high[1], lowc, highc); - - /* Copy information for the common file. - Return with a zero if any of the compares failed. */ - - for (d = 0; d < 2; d++) - for (ptr = using[d]; ptr; ptr = D_NEXT (ptr)) - { - int result_offset = D_LOWLINE (ptr, FC) - lowc; - - if (!copy_stringlist (D_LINEARRAY (ptr, FC), - D_LENARRAY (ptr, FC), - D_LINEARRAY (result, FILEC) + result_offset, - D_LENARRAY (result, FILEC) + result_offset, - D_NUMLINES (ptr, FC))) - return 0; - } - - /* Copy information for file d. First deal with anything that might be - before the first diff. */ - - for (d = 0; d < 2; d++) - { - struct diff_block *u = using[d]; - int lo = low[d], hi = high[d]; - - for (i = 0; - i + lo < (u ? D_LOWLINE (u, FO) : hi + 1); - i++) - { - D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, i); - D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, i); - } - - for (ptr = u; ptr; ptr = D_NEXT (ptr)) - { - int result_offset = D_LOWLINE (ptr, FO) - lo; - int linec; - - if (!copy_stringlist (D_LINEARRAY (ptr, FO), - D_LENARRAY (ptr, FO), - D_LINEARRAY (result, FILE0 + d) + result_offset, - D_LENARRAY (result, FILE0 + d) + result_offset, - D_NUMLINES (ptr, FO))) - return 0; - - /* Catch the lines between here and the next diff */ - linec = D_HIGHLINE (ptr, FC) + 1 - lowc; - for (i = D_HIGHLINE (ptr, FO) + 1 - lo; - i < (D_NEXT (ptr) ? D_LOWLINE (D_NEXT (ptr), FO) : hi + 1) - lo; - i++) - { - D_RELNUM (result, FILE0 + d, i) = D_RELNUM (result, FILEC, linec); - D_RELLEN (result, FILE0 + d, i) = D_RELLEN (result, FILEC, linec); - linec++; - } - } - } - - /* Set correspond */ - if (!using[0]) - D3_TYPE (result) = DIFF_2ND; - else if (!using[1]) - D3_TYPE (result) = DIFF_1ST; - else - { - int nl0 = D_NUMLINES (result, FILE0); - int nl1 = D_NUMLINES (result, FILE1); - - if (nl0 != nl1 - || !compare_line_list (D_LINEARRAY (result, FILE0), - D_LENARRAY (result, FILE0), - D_LINEARRAY (result, FILE1), - D_LENARRAY (result, FILE1), - nl0)) - D3_TYPE (result) = DIFF_ALL; - else - D3_TYPE (result) = DIFF_3RD; - } - - return result; -} - -/* - * This routine copies pointers from a list of strings to a different list - * of strings. If a spot in the second list is already filled, it - * makes sure that it is filled with the same string; if not it - * returns 0, the copy incomplete. - * Upon successful completion of the copy, it returns 1. - */ -static int -copy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum) - char * const fromptrs[]; - char *toptrs[]; - size_t const fromlengths[]; - size_t tolengths[]; - int copynum; -{ - register char * const *f = fromptrs; - register char **t = toptrs; - register size_t const *fl = fromlengths; - register size_t *tl = tolengths; - - while (copynum--) - { - if (*t) - { if (*fl != *tl || memcmp (*f, *t, *fl)) return 0; } - else - { *t = *f ; *tl = *fl; } - - t++; f++; tl++; fl++; - } - return 1; -} - -/* - * Create a diff3_block, with ranges as specified in the arguments. - * Allocate the arrays for the various pointers (and zero them) based - * on the arguments passed. Return the block as a result. - */ -static struct diff3_block * -create_diff3_block (low0, high0, low1, high1, low2, high2) - register int low0, high0, low1, high1, low2, high2; -{ - struct diff3_block *result = ALLOCATE (1, struct diff3_block); - int numlines; - - D3_TYPE (result) = ERROR; - D_NEXT (result) = 0; - - /* Assign ranges */ - D_LOWLINE (result, FILE0) = low0; - D_HIGHLINE (result, FILE0) = high0; - D_LOWLINE (result, FILE1) = low1; - D_HIGHLINE (result, FILE1) = high1; - D_LOWLINE (result, FILE2) = low2; - D_HIGHLINE (result, FILE2) = high2; - - /* Allocate and zero space */ - numlines = D_NUMLINES (result, FILE0); - if (numlines) - { - D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *); - D_LENARRAY (result, FILE0) = ALLOCATE (numlines, size_t); - bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *))); - bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (size_t))); - } - else - { - D_LINEARRAY (result, FILE0) = 0; - D_LENARRAY (result, FILE0) = 0; - } - - numlines = D_NUMLINES (result, FILE1); - if (numlines) - { - D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *); - D_LENARRAY (result, FILE1) = ALLOCATE (numlines, size_t); - bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *))); - bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (size_t))); - } - else - { - D_LINEARRAY (result, FILE1) = 0; - D_LENARRAY (result, FILE1) = 0; - } - - numlines = D_NUMLINES (result, FILE2); - if (numlines) - { - D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *); - D_LENARRAY (result, FILE2) = ALLOCATE (numlines, size_t); - bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *))); - bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (size_t))); - } - else - { - D_LINEARRAY (result, FILE2) = 0; - D_LENARRAY (result, FILE2) = 0; - } - - /* Return */ - return result; -} - -/* - * Compare two lists of lines of text. - * Return 1 if they are equivalent, 0 if not. - */ -static int -compare_line_list (list1, lengths1, list2, lengths2, nl) - char * const list1[], * const list2[]; - size_t const lengths1[], lengths2[]; - int nl; -{ - char - * const *l1 = list1, - * const *l2 = list2; - size_t const - *lgths1 = lengths1, - *lgths2 = lengths2; - - while (nl--) - if (!*l1 || !*l2 || *lgths1 != *lgths2++ - || memcmp (*l1++, *l2++, *lgths1++)) - return 0; - return 1; -} - -/* - * Routines to input and parse two way diffs. - */ - -extern char **environ; - -static struct diff_block * -process_diff (filea, fileb, last_block) - char const *filea, *fileb; - struct diff_block **last_block; -{ - char *diff_contents; - char *diff_limit; - char *scan_diff; - enum diff_type dt; - int i; - struct diff_block *block_list, **block_list_end, *bptr; - - diff_limit = read_diff (filea, fileb, &diff_contents); - scan_diff = diff_contents; - block_list_end = &block_list; - bptr = 0; /* Pacify `gcc -W'. */ - - while (scan_diff < diff_limit) - { - bptr = ALLOCATE (1, struct diff_block); - bptr->lines[0] = bptr->lines[1] = 0; - bptr->lengths[0] = bptr->lengths[1] = 0; - - dt = process_diff_control (&scan_diff, bptr); - if (dt == ERROR || *scan_diff != '\n') - { - fprintf (stderr, "%s: diff error: ", program_name); - do - { - putc (*scan_diff, stderr); - } - while (*scan_diff++ != '\n'); - exit (2); - } - scan_diff++; - - /* Force appropriate ranges to be null, if necessary */ - switch (dt) - { - case ADD: - bptr->ranges[0][0]++; - break; - case DELETE: - bptr->ranges[1][0]++; - break; - case CHANGE: - break; - default: - fatal ("internal error: invalid diff type in process_diff"); - break; - } - - /* Allocate space for the pointers for the lines from filea, and - parcel them out among these pointers */ - if (dt != ADD) - { - int numlines = D_NUMLINES (bptr, 0); - bptr->lines[0] = ALLOCATE (numlines, char *); - bptr->lengths[0] = ALLOCATE (numlines, size_t); - for (i = 0; i < numlines; i++) - scan_diff = scan_diff_line (scan_diff, - &(bptr->lines[0][i]), - &(bptr->lengths[0][i]), - diff_limit, - '<'); - } - - /* Get past the separator for changes */ - if (dt == CHANGE) - { - if (strncmp (scan_diff, "---\n", 4)) - fatal ("invalid diff format; invalid change separator"); - scan_diff += 4; - } - - /* Allocate space for the pointers for the lines from fileb, and - parcel them out among these pointers */ - if (dt != DELETE) - { - int numlines = D_NUMLINES (bptr, 1); - bptr->lines[1] = ALLOCATE (numlines, char *); - bptr->lengths[1] = ALLOCATE (numlines, size_t); - for (i = 0; i < numlines; i++) - scan_diff = scan_diff_line (scan_diff, - &(bptr->lines[1][i]), - &(bptr->lengths[1][i]), - diff_limit, - '>'); - } - - /* Place this block on the blocklist. */ - *block_list_end = bptr; - block_list_end = &bptr->next; - } - - *block_list_end = 0; - *last_block = bptr; - return block_list; -} - -/* - * This routine will parse a normal format diff control string. It - * returns the type of the diff (ERROR if the format is bad). All of - * the other important information is filled into to the structure - * pointed to by db, and the string pointer (whose location is passed - * to this routine) is updated to point beyond the end of the string - * parsed. Note that only the ranges in the diff_block will be set by - * this routine. - * - * If some specific pair of numbers has been reduced to a single - * number, then both corresponding numbers in the diff block are set - * to that number. In general these numbers are interpetted as ranges - * inclusive, unless being used by the ADD or DELETE commands. It is - * assumed that these will be special cased in a superior routine. - */ - -static enum diff_type -process_diff_control (string, db) - char **string; - struct diff_block *db; -{ - char *s = *string; - int holdnum; - enum diff_type type; - -/* These macros are defined here because they can use variables - defined in this function. Don't try this at home kids, we're - trained professionals! - - Also note that SKIPWHITE only recognizes tabs and spaces, and - that READNUM can only read positive, integral numbers */ - -#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; } -#define READNUM(s, num) \ - { unsigned char c = *s; if (!ISDIGIT (c)) return ERROR; holdnum = 0; \ - do { holdnum = (c - '0' + holdnum * 10); } \ - while (ISDIGIT (c = *++s)); (num) = holdnum; } - - /* Read first set of digits */ - SKIPWHITE (s); - READNUM (s, db->ranges[0][START]); - - /* Was that the only digit? */ - SKIPWHITE (s); - if (*s == ',') - { - /* Get the next digit */ - s++; - READNUM (s, db->ranges[0][END]); - } - else - db->ranges[0][END] = db->ranges[0][START]; - - /* Get the letter */ - SKIPWHITE (s); - switch (*s) - { - case 'a': - type = ADD; - break; - case 'c': - type = CHANGE; - break; - case 'd': - type = DELETE; - break; - default: - return ERROR; /* Bad format */ - } - s++; /* Past letter */ - - /* Read second set of digits */ - SKIPWHITE (s); - READNUM (s, db->ranges[1][START]); - - /* Was that the only digit? */ - SKIPWHITE (s); - if (*s == ',') - { - /* Get the next digit */ - s++; - READNUM (s, db->ranges[1][END]); - SKIPWHITE (s); /* To move to end */ - } - else - db->ranges[1][END] = db->ranges[1][START]; - - *string = s; - return type; -} - -static char * -read_diff (filea, fileb, output_placement) - char const *filea, *fileb; - char **output_placement; -{ - char *diff_result; - size_t bytes, current_chunk_size, total; - int fd, wstatus; - struct stat pipestat; - - /* 302 / 1000 is log10(2.0) rounded up. Subtract 1 for the sign bit; - add 1 for integer division truncation; add 1 more for a minus sign. */ -#define INT_STRLEN_BOUND(type) ((sizeof(type)*CHAR_BIT - 1) * 302 / 1000 + 2) - -#if HAVE_FORK - - char const *argv[7]; - char horizon_arg[17 + INT_STRLEN_BOUND (int)]; - char const **ap; - int fds[2]; - pid_t pid; - - ap = argv; - *ap++ = diff_program; - if (always_text) - *ap++ = "-a"; - sprintf (horizon_arg, "--horizon-lines=%d", horizon_lines); - *ap++ = horizon_arg; - *ap++ = "--"; - *ap++ = filea; - *ap++ = fileb; - *ap = 0; - - if (pipe (fds) != 0) - perror_with_exit ("pipe"); - - pid = vfork (); - if (pid == 0) - { - /* Child */ - close (fds[0]); - if (fds[1] != STDOUT_FILENO) - { - dup2 (fds[1], STDOUT_FILENO); - close (fds[1]); - } - execve (diff_program, (char **) argv, environ); - /* Avoid stdio, because the parent process's buffers are inherited. */ - write (STDERR_FILENO, diff_program, strlen (diff_program)); - write (STDERR_FILENO, ": not found\n", 12); - _exit (2); - } - - if (pid == -1) - perror_with_exit ("fork failed"); - - close (fds[1]); /* Prevent erroneous lack of EOF */ - fd = fds[0]; - -#else /* ! HAVE_FORK */ - - FILE *fpipe; - char *command = xmalloc (sizeof (diff_program) + 30 + INT_STRLEN_BOUND (int) - + 4 * (strlen (filea) + strlen (fileb))); - char *p; - sprintf (command, "%s -a --horizon-lines=%d -- ", - diff_program, horizon_lines); - p = command + strlen (command); - SYSTEM_QUOTE_ARG (p, filea); - *p++ = ' '; - SYSTEM_QUOTE_ARG (p, fileb); - *p = '\0'; - fpipe = popen (command, "r"); - if (!fpipe) - perror_with_exit (command); - free (command); - fd = fileno (fpipe); - -#endif /* ! HAVE_FORK */ - - current_chunk_size = 8 * 1024; - if (fstat (fd, &pipestat) == 0) - current_chunk_size = max (current_chunk_size, STAT_BLOCKSIZE (pipestat)); - - diff_result = xmalloc (current_chunk_size); - total = 0; - do { - bytes = myread (fd, - diff_result + total, - current_chunk_size - total); - total += bytes; - if (total == current_chunk_size) - { - if (current_chunk_size < 2 * current_chunk_size) - current_chunk_size = 2 * current_chunk_size; - else if (current_chunk_size < (size_t) -1) - current_chunk_size = (size_t) -1; - else - fatal ("files are too large to fit into memory"); - diff_result = xrealloc (diff_result, (current_chunk_size *= 2)); - } - } while (bytes); - - if (total != 0 && diff_result[total-1] != '\n') - fatal ("invalid diff format; incomplete last line"); - - *output_placement = diff_result; - -#if ! HAVE_FORK - - wstatus = pclose (fpipe); - -#else /* HAVE_FORK */ - - if (close (fd) != 0) - perror_with_exit ("pipe close"); - if (waitpid (pid, &wstatus, 0) < 0) - perror_with_exit ("waitpid failed"); - -#endif /* HAVE_FORK */ - - if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) - fatal ("subsidiary diff failed"); - - return diff_result + total; -} - - -/* - * Scan a regular diff line (consisting of > or <, followed by a - * space, followed by text (including nulls) up to a newline. - * - * This next routine began life as a macro and many parameters in it - * are used as call-by-reference values. - */ -static char * -scan_diff_line (scan_ptr, set_start, set_length, limit, leadingchar) - char *scan_ptr, **set_start; - size_t *set_length; - char *limit; - int leadingchar; -{ - char *line_ptr; - - if (!(scan_ptr[0] == leadingchar - && scan_ptr[1] == ' ')) - fatal ("invalid diff format; incorrect leading line chars"); - - *set_start = line_ptr = scan_ptr + 2; - while (*line_ptr++ != '\n') - ; - - /* Include newline if the original line ended in a newline, - or if an edit script is being generated. - Copy any missing newline message to stderr if an edit script is being - generated, because edit scripts cannot handle missing newlines. - Return the beginning of the next line. */ - *set_length = line_ptr - *set_start; - if (line_ptr < limit && *line_ptr == '\\') - { - if (edscript) - fprintf (stderr, "%s:", program_name); - else - --*set_length; - line_ptr++; - do - { - if (edscript) - putc (*line_ptr, stderr); - } - while (*line_ptr++ != '\n'); - } - - return line_ptr; -} - -/* - * This routine outputs a three way diff passed as a list of - * diff3_block's. - * The argument MAPPING is indexed by external file number (in the - * argument list) and contains the internal file number (from the - * diff passed). This is important because the user expects his - * outputs in terms of the argument list number, and the diff passed - * may have been done slightly differently (if the last argument - * was "-", for example). - * REV_MAPPING is the inverse of MAPPING. - */ -static void -output_diff3 (outputfile, diff, mapping, rev_mapping) - FILE *outputfile; - struct diff3_block *diff; - int const mapping[3], rev_mapping[3]; -{ - int i; - int oddoneout; - char *cp; - struct diff3_block *ptr; - int line; - size_t length; - int dontprint; - static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */ - char const *line_prefix = tab_align_flag ? "\t" : " "; - - for (ptr = diff; ptr; ptr = D_NEXT (ptr)) - { - char x[2]; - - switch (ptr->correspond) - { - case DIFF_ALL: - x[0] = '\0'; - dontprint = 3; /* Print them all */ - oddoneout = 3; /* Nobody's odder than anyone else */ - break; - case DIFF_1ST: - case DIFF_2ND: - case DIFF_3RD: - oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST]; - - x[0] = oddoneout + '1'; - x[1] = '\0'; - dontprint = oddoneout==0; - break; - default: - fatal ("internal error: invalid diff type passed to output"); - } - fprintf (outputfile, "====%s\n", x); - - /* Go 0, 2, 1 if the first and third outputs are equivalent. */ - for (i = 0; i < 3; - i = (oddoneout == 1 ? skew_increment[i] : i + 1)) - { - int realfile = mapping[i]; - int - lowt = D_LOWLINE (ptr, realfile), - hight = D_HIGHLINE (ptr, realfile); - - fprintf (outputfile, "%d:", i + 1); - switch (lowt - hight) - { - case 1: - fprintf (outputfile, "%da\n", lowt - 1); - break; - case 0: - fprintf (outputfile, "%dc\n", lowt); - break; - default: - fprintf (outputfile, "%d,%dc\n", lowt, hight); - break; - } - - if (i == dontprint) continue; - - if (lowt <= hight) - { - line = 0; - do - { - fprintf (outputfile, line_prefix); - cp = D_RELNUM (ptr, realfile, line); - length = D_RELLEN (ptr, realfile, line); - fwrite (cp, sizeof (char), length, outputfile); - } - while (++line < hight - lowt + 1); - if (cp[length - 1] != '\n') - fprintf (outputfile, "\n\\ No newline at end of file\n"); - } - } - } -} - - -/* - * Output to OUTPUTFILE the lines of B taken from FILENUM. - * Double any initial '.'s; yield nonzero if any initial '.'s were doubled. - */ -static int -dotlines (outputfile, b, filenum) - FILE *outputfile; - struct diff3_block *b; - int filenum; -{ - int i; - int leading_dot = 0; - - for (i = 0; - i < D_NUMLINES (b, filenum); - i++) - { - char *line = D_RELNUM (b, filenum, i); - if (line[0] == '.') - { - leading_dot = 1; - fprintf (outputfile, "."); - } - fwrite (line, sizeof (char), - D_RELLEN (b, filenum, i), outputfile); - } - - return leading_dot; -} - -/* - * Output to OUTPUTFILE a '.' line. If LEADING_DOT is nonzero, - * also output a command that removes initial '.'s - * starting with line START and continuing for NUM lines. - */ -static void -undotlines (outputfile, leading_dot, start, num) - FILE *outputfile; - int leading_dot, start, num; -{ - fprintf (outputfile, ".\n"); - if (leading_dot) - if (num == 1) - fprintf (outputfile, "%ds/^\\.//\n", start); - else - fprintf (outputfile, "%d,%ds/^\\.//\n", start, start + num - 1); -} - -/* - * This routine outputs a diff3 set of blocks as an ed script. This - * script applies the changes between file's 2 & 3 to file 1. It - * takes the precise format of the ed script to be output from global - * variables set during options processing. Note that it does - * destructive things to the set of diff3 blocks it is passed; it - * reverses their order (this gets around the problems involved with - * changing line numbers in an ed script). - * - * Note that this routine has the same problem of mapping as the last - * one did; the variable MAPPING maps from file number according to - * the argument list to file number according to the diff passed. All - * files listed below are in terms of the argument list. - * REV_MAPPING is the inverse of MAPPING. - * - * The arguments FILE0, FILE1 and FILE2 are the strings to print - * as the names of the three files. These may be the actual names, - * or may be the arguments specified with -L. - * - * Returns 1 if conflicts were found. - */ - -static int -output_diff3_edscript (outputfile, diff, mapping, rev_mapping, - file0, file1, file2) - FILE *outputfile; - struct diff3_block *diff; - int const mapping[3], rev_mapping[3]; - char const *file0, *file1, *file2; -{ - int leading_dot; - int conflicts_found = 0, conflict; - struct diff3_block *b; - - for (b = reverse_diff3_blocklist (diff); b; b = b->next) - { - /* Must do mapping correctly. */ - enum diff_type type - = ((b->correspond == DIFF_ALL) ? - DIFF_ALL : - ((enum diff_type) - (((int) DIFF_1ST) - + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); - - /* If we aren't supposed to do this output block, skip it. */ - switch (type) - { - default: continue; - case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; - case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; - case DIFF_ALL: if (simple_only) continue; conflict = flagging; break; - } - - if (conflict) - { - conflicts_found = 1; - - - /* Mark end of conflict. */ - - fprintf (outputfile, "%da\n", D_HIGHLINE (b, mapping[FILE0])); - leading_dot = 0; - if (type == DIFF_ALL) - { - if (show_2nd) - { - /* Append lines from FILE1. */ - fprintf (outputfile, "||||||| %s\n", file1); - leading_dot = dotlines (outputfile, b, mapping[FILE1]); - } - /* Append lines from FILE2. */ - fprintf (outputfile, "=======\n"); - leading_dot |= dotlines (outputfile, b, mapping[FILE2]); - } - fprintf (outputfile, ">>>>>>> %s\n", file2); - undotlines (outputfile, leading_dot, - D_HIGHLINE (b, mapping[FILE0]) + 2, - (D_NUMLINES (b, mapping[FILE1]) - + D_NUMLINES (b, mapping[FILE2]) + 1)); - - - /* Mark start of conflict. */ - - fprintf (outputfile, "%da\n<<<<<<< %s\n", - D_LOWLINE (b, mapping[FILE0]) - 1, - type == DIFF_ALL ? file0 : file1); - leading_dot = 0; - if (type == DIFF_2ND) - { - /* Prepend lines from FILE1. */ - leading_dot = dotlines (outputfile, b, mapping[FILE1]); - fprintf (outputfile, "=======\n"); - } - undotlines (outputfile, leading_dot, - D_LOWLINE (b, mapping[FILE0]) + 1, - D_NUMLINES (b, mapping[FILE1])); - } - else if (D_NUMLINES (b, mapping[FILE2]) == 0) - /* Write out a delete */ - { - if (D_NUMLINES (b, mapping[FILE0]) == 1) - fprintf (outputfile, "%dd\n", - D_LOWLINE (b, mapping[FILE0])); - else - fprintf (outputfile, "%d,%dd\n", - D_LOWLINE (b, mapping[FILE0]), - D_HIGHLINE (b, mapping[FILE0])); - } - else - /* Write out an add or change */ - { - switch (D_NUMLINES (b, mapping[FILE0])) - { - case 0: - fprintf (outputfile, "%da\n", - D_HIGHLINE (b, mapping[FILE0])); - break; - case 1: - fprintf (outputfile, "%dc\n", - D_HIGHLINE (b, mapping[FILE0])); - break; - default: - fprintf (outputfile, "%d,%dc\n", - D_LOWLINE (b, mapping[FILE0]), - D_HIGHLINE (b, mapping[FILE0])); - break; - } - - undotlines (outputfile, dotlines (outputfile, b, mapping[FILE2]), - D_LOWLINE (b, mapping[FILE0]), - D_NUMLINES (b, mapping[FILE2])); - } - } - if (finalwrite) fprintf (outputfile, "w\nq\n"); - return conflicts_found; -} - -/* - * Read from INFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF - * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]', - * except that it works even for binary data or incomplete lines. - * - * As before, MAPPING maps from arg list file number to diff file number, - * REV_MAPPING is its inverse, - * and FILE0, FILE1, and FILE2 are the names of the files. - * - * Returns 1 if conflicts were found. - */ - -static int -output_diff3_merge (infile, outputfile, diff, mapping, rev_mapping, - file0, file1, file2) - FILE *infile, *outputfile; - struct diff3_block *diff; - int const mapping[3], rev_mapping[3]; - char const *file0, *file1, *file2; -{ - int c, i; - int conflicts_found = 0, conflict; - struct diff3_block *b; - int linesread = 0; - - for (b = diff; b; b = b->next) - { - /* Must do mapping correctly. */ - enum diff_type type - = ((b->correspond == DIFF_ALL) ? - DIFF_ALL : - ((enum diff_type) - (((int) DIFF_1ST) - + rev_mapping[(int) b->correspond - (int) DIFF_1ST]))); - char const *format_2nd = "<<<<<<< %s\n"; - - /* If we aren't supposed to do this output block, skip it. */ - switch (type) - { - default: continue; - case DIFF_2ND: if (!show_2nd) continue; conflict = 1; break; - case DIFF_3RD: if (overlap_only) continue; conflict = 0; break; - case DIFF_ALL: if (simple_only) continue; conflict = flagging; - format_2nd = "||||||| %s\n"; - break; - } - - /* Copy I lines from file 0. */ - i = D_LOWLINE (b, FILE0) - linesread - 1; - linesread += i; - while (0 <= --i) - do - { - c = getc (infile); - if (c == EOF) - if (ferror (infile)) - perror_with_exit ("input file"); - else if (feof (infile)) - fatal ("input file shrank"); - putc (c, outputfile); - } - while (c != '\n'); - - if (conflict) - { - conflicts_found = 1; - - if (type == DIFF_ALL) - { - /* Put in lines from FILE0 with bracket. */ - fprintf (outputfile, "<<<<<<< %s\n", file0); - for (i = 0; - i < D_NUMLINES (b, mapping[FILE0]); - i++) - fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char), - D_RELLEN (b, mapping[FILE0], i), outputfile); - } - - if (show_2nd) - { - /* Put in lines from FILE1 with bracket. */ - fprintf (outputfile, format_2nd, file1); - for (i = 0; - i < D_NUMLINES (b, mapping[FILE1]); - i++) - fwrite (D_RELNUM (b, mapping[FILE1], i), sizeof (char), - D_RELLEN (b, mapping[FILE1], i), outputfile); - } - - fprintf (outputfile, "=======\n"); - } - - /* Put in lines from FILE2. */ - for (i = 0; - i < D_NUMLINES (b, mapping[FILE2]); - i++) - fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char), - D_RELLEN (b, mapping[FILE2], i), outputfile); - - if (conflict) - fprintf (outputfile, ">>>>>>> %s\n", file2); - - /* Skip I lines in file 0. */ - i = D_NUMLINES (b, FILE0); - linesread += i; - while (0 <= --i) - while ((c = getc (infile)) != '\n') - if (c == EOF) - if (ferror (infile)) - perror_with_exit ("input file"); - else if (feof (infile)) - { - if (i || b->next) - fatal ("input file shrank"); - return conflicts_found; - } - } - /* Copy rest of common file. */ - while ((c = getc (infile)) != EOF || !(ferror (infile) | feof (infile))) - putc (c, outputfile); - return conflicts_found; -} - -/* - * Reverse the order of the list of diff3 blocks. - */ -static struct diff3_block * -reverse_diff3_blocklist (diff) - struct diff3_block *diff; -{ - register struct diff3_block *tmp, *next, *prev; - - for (tmp = diff, prev = 0; tmp; tmp = next) - { - next = tmp->next; - tmp->next = prev; - prev = tmp; - } - - return prev; -} - -static size_t -myread (fd, ptr, size) - int fd; - char *ptr; - size_t size; -{ - size_t result = read (fd, ptr, size); - if (result == -1) - perror_with_exit ("read failed"); - return result; -} - -static VOID * -xmalloc (size) - size_t size; -{ - VOID *result = (VOID *) malloc (size ? size : 1); - if (!result) - fatal ("memory exhausted"); - return result; -} - -static VOID * -xrealloc (ptr, size) - VOID *ptr; - size_t size; -{ - VOID *result = (VOID *) realloc (ptr, size ? size : 1); - if (!result) - fatal ("memory exhausted"); - return result; -} - -static void -fatal (string) - char const *string; -{ - fprintf (stderr, "%s: %s\n", program_name, string); - exit (2); -} - -static void -perror_with_exit (string) - char const *string; -{ - int e = errno; - fprintf (stderr, "%s: ", program_name); - errno = e; - perror (string); - exit (2); -} diff --git a/gnu/usr.bin/diff/dir.c b/gnu/usr.bin/diff/dir.c deleted file mode 100644 index 036a86f1128e..000000000000 --- a/gnu/usr.bin/diff/dir.c +++ /dev/null @@ -1,216 +0,0 @@ -/* Read, sort and compare two directories. Used for GNU DIFF. - Copyright (C) 1988, 1989, 1992, 1993, 1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "diff.h" - -/* Read the directory named by DIR and store into DIRDATA a sorted vector - of filenames for its contents. DIR->desc == -1 means this directory is - known to be nonexistent, so set DIRDATA to an empty vector. - Return -1 (setting errno) if error, 0 otherwise. */ - -struct dirdata -{ - char const **names; /* Sorted names of files in dir, 0-terminated. */ - char *data; /* Allocated storage for file names. */ -}; - -static int compare_names PARAMS((void const *, void const *)); -static int dir_sort PARAMS((struct file_data const *, struct dirdata *)); - -static int -dir_sort (dir, dirdata) - struct file_data const *dir; - struct dirdata *dirdata; -{ - register struct dirent *next; - register int i; - - /* Address of block containing the files that are described. */ - char const **names; - - /* Number of files in directory. */ - size_t nnames; - - /* Allocated and used storage for file name data. */ - char *data; - size_t data_alloc, data_used; - - dirdata->names = 0; - dirdata->data = 0; - nnames = 0; - data = 0; - - if (dir->desc != -1) - { - /* Open the directory and check for errors. */ - register DIR *reading = opendir (dir->name); - if (!reading) - return -1; - - /* Initialize the table of filenames. */ - - data_alloc = max (1, (size_t) dir->stat.st_size); - data_used = 0; - dirdata->data = data = xmalloc (data_alloc); - - /* Read the directory entries, and insert the subfiles - into the `data' table. */ - - while ((errno = 0, (next = readdir (reading)) != 0)) - { - char *d_name = next->d_name; - size_t d_size = NAMLEN (next) + 1; - - /* Ignore the files `.' and `..' */ - if (d_name[0] == '.' - && (d_name[1] == 0 || (d_name[1] == '.' && d_name[2] == 0))) - continue; - - if (excluded_filename (d_name)) - continue; - - while (data_alloc < data_used + d_size) - dirdata->data = data = xrealloc (data, data_alloc *= 2); - memcpy (data + data_used, d_name, d_size); - data_used += d_size; - nnames++; - } - if (errno) - { - int e = errno; - closedir (reading); - errno = e; - return -1; - } -#if CLOSEDIR_VOID - closedir (reading); -#else - if (closedir (reading) != 0) - return -1; -#endif - } - - /* Create the `names' table from the `data' table. */ - dirdata->names = names = (char const **) xmalloc (sizeof (char *) - * (nnames + 1)); - for (i = 0; i < nnames; i++) - { - names[i] = data; - data += strlen (data) + 1; - } - names[nnames] = 0; - - /* Sort the table. */ - qsort (names, nnames, sizeof (char *), compare_names); - - return 0; -} - -/* Sort the files now in the table. */ - -static int -compare_names (file1, file2) - void const *file1, *file2; -{ - return filename_cmp (* (char const *const *) file1, - * (char const *const *) file2); -} - -/* Compare the contents of two directories named in FILEVEC[0] and FILEVEC[1]. - This is a top-level routine; it does everything necessary for diff - on two directories. - - FILEVEC[0].desc == -1 says directory FILEVEC[0] doesn't exist, - but pretend it is empty. Likewise for FILEVEC[1]. - - HANDLE_FILE is a caller-provided subroutine called to handle each file. - It gets five operands: dir and name (rel to original working dir) of file - in dir 0, dir and name pathname of file in dir 1, and the recursion depth. - - For a file that appears in only one of the dirs, one of the name-args - to HANDLE_FILE is zero. - - DEPTH is the current depth in recursion, used for skipping top-level - files by the -S option. - - Returns the maximum of all the values returned by HANDLE_FILE, - or 2 if trouble is encountered in opening files. */ - -int -diff_dirs (filevec, handle_file, depth) - struct file_data const filevec[]; - int (*handle_file) PARAMS((char const *, char const *, char const *, char const *, int)); - int depth; -{ - struct dirdata dirdata[2]; - int val = 0; /* Return value. */ - int i; - - /* Get sorted contents of both dirs. */ - for (i = 0; i < 2; i++) - if (dir_sort (&filevec[i], &dirdata[i]) != 0) - { - perror_with_name (filevec[i].name); - val = 2; - } - - if (val == 0) - { - register char const * const *names0 = dirdata[0].names; - register char const * const *names1 = dirdata[1].names; - char const *name0 = filevec[0].name; - char const *name1 = filevec[1].name; - - /* If `-S name' was given, and this is the topmost level of comparison, - ignore all file names less than the specified starting name. */ - - if (dir_start_file && depth == 0) - { - while (*names0 && filename_cmp (*names0, dir_start_file) < 0) - names0++; - while (*names1 && filename_cmp (*names1, dir_start_file) < 0) - names1++; - } - - /* Loop while files remain in one or both dirs. */ - while (*names0 || *names1) - { - /* Compare next name in dir 0 with next name in dir 1. - At the end of a dir, - pretend the "next name" in that dir is very large. */ - int nameorder = (!*names0 ? 1 : !*names1 ? -1 - : filename_cmp (*names0, *names1)); - int v1 = (*handle_file) (name0, 0 < nameorder ? 0 : *names0++, - name1, nameorder < 0 ? 0 : *names1++, - depth + 1); - if (v1 > val) - val = v1; - } - } - - for (i = 0; i < 2; i++) - { - if (dirdata[i].names) - free (dirdata[i].names); - if (dirdata[i].data) - free (dirdata[i].data); - } - - return val; -} diff --git a/gnu/usr.bin/diff/ed.c b/gnu/usr.bin/diff/ed.c deleted file mode 100644 index 717ef358d0ee..000000000000 --- a/gnu/usr.bin/diff/ed.c +++ /dev/null @@ -1,200 +0,0 @@ -/* Output routines for ed-script format. - Copyright (C) 1988, 89, 91, 92, 93 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "diff.h" - -static void print_ed_hunk PARAMS((struct change *)); -static void print_rcs_hunk PARAMS((struct change *)); -static void pr_forward_ed_hunk PARAMS((struct change *)); - -/* Print our script as ed commands. */ - -void -print_ed_script (script) - struct change *script; -{ - print_script (script, find_reverse_change, print_ed_hunk); -} - -/* Print a hunk of an ed diff */ - -static void -print_ed_hunk (hunk) - struct change *hunk; -{ - int f0, l0, f1, l1; - int deletes, inserts; - -#if 0 - hunk = flip_script (hunk); -#endif -#ifdef DEBUG - debug_script (hunk); -#endif - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts); - if (!deletes && !inserts) - return; - - begin_output (); - - /* Print out the line number header for this hunk */ - print_number_range (',', &files[0], f0, l0); - fprintf (outfile, "%c\n", change_letter (inserts, deletes)); - - /* Print new/changed lines from second file, if needed */ - if (inserts) - { - int i; - int inserting = 1; - for (i = f1; i <= l1; i++) - { - /* Resume the insert, if we stopped. */ - if (! inserting) - fprintf (outfile, "%da\n", - i - f1 + translate_line_number (&files[0], f0) - 1); - inserting = 1; - - /* If the file's line is just a dot, it would confuse `ed'. - So output it with a double dot, and set the flag LEADING_DOT - so that we will output another ed-command later - to change the double dot into a single dot. */ - - if (files[1].linbuf[i][0] == '.' - && files[1].linbuf[i][1] == '\n') - { - fprintf (outfile, "..\n"); - fprintf (outfile, ".\n"); - /* Now change that double dot to the desired single dot. */ - fprintf (outfile, "%ds/^\\.\\././\n", - i - f1 + translate_line_number (&files[0], f0)); - inserting = 0; - } - else - /* Line is not `.', so output it unmodified. */ - print_1_line ("", &files[1].linbuf[i]); - } - - /* End insert mode, if we are still in it. */ - if (inserting) - fprintf (outfile, ".\n"); - } -} - -/* Print change script in the style of ed commands, - but print the changes in the order they appear in the input files, - which means that the commands are not truly useful with ed. */ - -void -pr_forward_ed_script (script) - struct change *script; -{ - print_script (script, find_change, pr_forward_ed_hunk); -} - -static void -pr_forward_ed_hunk (hunk) - struct change *hunk; -{ - int i; - int f0, l0, f1, l1; - int deletes, inserts; - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts); - if (!deletes && !inserts) - return; - - begin_output (); - - fprintf (outfile, "%c", change_letter (inserts, deletes)); - print_number_range (' ', files, f0, l0); - fprintf (outfile, "\n"); - - /* If deletion only, print just the number range. */ - - if (!inserts) - return; - - /* For insertion (with or without deletion), print the number range - and the lines from file 2. */ - - for (i = f1; i <= l1; i++) - print_1_line ("", &files[1].linbuf[i]); - - fprintf (outfile, ".\n"); -} - -/* Print in a format somewhat like ed commands - except that each insert command states the number of lines it inserts. - This format is used for RCS. */ - -void -print_rcs_script (script) - struct change *script; -{ - print_script (script, find_change, print_rcs_hunk); -} - -/* Print a hunk of an RCS diff */ - -static void -print_rcs_hunk (hunk) - struct change *hunk; -{ - int i; - int f0, l0, f1, l1; - int deletes, inserts; - int tf0, tl0, tf1, tl1; - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk, &f0, &l0, &f1, &l1, &deletes, &inserts); - if (!deletes && !inserts) - return; - - begin_output (); - - translate_range (&files[0], f0, l0, &tf0, &tl0); - - if (deletes) - { - fprintf (outfile, "d"); - /* For deletion, print just the starting line number from file 0 - and the number of lines deleted. */ - fprintf (outfile, "%d %d\n", - tf0, - (tl0 >= tf0 ? tl0 - tf0 + 1 : 1)); - } - - if (inserts) - { - fprintf (outfile, "a"); - - /* Take last-line-number from file 0 and # lines from file 1. */ - translate_range (&files[1], f1, l1, &tf1, &tl1); - fprintf (outfile, "%d %d\n", - tl0, - (tl1 >= tf1 ? tl1 - tf1 + 1 : 1)); - - /* Print the inserted lines. */ - for (i = f1; i <= l1; i++) - print_1_line ("", &files[1].linbuf[i]); - } -} diff --git a/gnu/usr.bin/diff/getopt.c b/gnu/usr.bin/diff/getopt.c deleted file mode 100644 index 21fa7fad2861..000000000000 --- a/gnu/usr.bin/diff/getopt.c +++ /dev/null @@ -1,748 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 - Free Software Foundation, Inc. - - This program 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. - - This program 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; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in . - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef __STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#if defined(__GNU_LIBRARY__) || defined(__NetBSD__) -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include -#endif /* GNU C library. */ - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = NULL; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* XXX 1003.2 says this must be 1 before any call. */ -int optind = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return EOF with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#if defined(__GNU_LIBRARY__) || defined(__NetBSD__) -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include -#define my_index strchr -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -char *getenv (); - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -#ifndef __STDC__ -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -#endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -static const char * -_getopt_initialize (optstring) - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns `EOF'. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - optarg = NULL; - - if (optind == 0) - optstring = _getopt_initialize (optstring); - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc - && (argv[optind][0] != '-' || argv[optind][1] == '\0')) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return EOF; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) - { - if (ordering == REQUIRE_ORDER) - return EOF; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if (nameend - nextchar == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous\n", - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[optind - 1][0], pfound->name); - } - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, "%s: unrecognized option `--%s'\n", - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, "%s: unrecognized option `%c%s'\n", - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); - else - fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); - } - optopt = c; - return '?'; - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: option requires an argument -- %c\n", - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == EOF) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/gnu/usr.bin/diff/getopt.h b/gnu/usr.bin/diff/getopt.h deleted file mode 100644 index 45541f5ac0f9..000000000000 --- a/gnu/usr.bin/diff/getopt.h +++ /dev/null @@ -1,129 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. - - This program 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. - - This program 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; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns EOF, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if __STDC__ -#if defined(__GNU_LIBRARY__) -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* not __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff --git a/gnu/usr.bin/diff/getopt1.c b/gnu/usr.bin/diff/getopt1.c deleted file mode 100644 index 725c653bbcc2..000000000000 --- a/gnu/usr.bin/diff/getopt1.c +++ /dev/null @@ -1,180 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 - Free Software Foundation, Inc. - - This program 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. - - This program 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; if not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "getopt.h" - -#ifndef __STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#else -char *getenv (); -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* _LIBC or not __GNU_LIBRARY__. */ - -#ifdef TEST - -#include - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == EOF) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/gnu/usr.bin/diff/ifdef.c b/gnu/usr.bin/diff/ifdef.c deleted file mode 100644 index 2834cbdfa236..000000000000 --- a/gnu/usr.bin/diff/ifdef.c +++ /dev/null @@ -1,428 +0,0 @@ -/* #ifdef-format output routines for GNU DIFF. - Copyright (C) 1989, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. - -This file is part of GNU DIFF. - -GNU DIFF is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY. No author or distributor -accepts responsibility to anyone for the consequences of using it -or for whether it serves any particular purpose or works at all, -unless he says so in writing. Refer to the GNU DIFF General Public -License for full details. - -Everyone is granted permission to copy, modify and redistribute -GNU DIFF, but only under the conditions described in the -GNU DIFF General Public License. A copy of this license is -supposed to have been given to you along with GNU DIFF so you -can know your rights and responsibilities. It should be in a -file named COPYING. Among other things, the copyright notice -and this notice must be preserved on all copies. */ - - -#include "diff.h" - -struct group -{ - struct file_data const *file; - int from, upto; /* start and limit lines for this group of lines */ -}; - -static char *format_group PARAMS((FILE *, char *, int, struct group const *)); -static char *scan_char_literal PARAMS((char *, int *)); -static char *scan_printf_spec PARAMS((char *)); -static int groups_letter_value PARAMS((struct group const *, int)); -static void format_ifdef PARAMS((char *, int, int, int, int)); -static void print_ifdef_hunk PARAMS((struct change *)); -static void print_ifdef_lines PARAMS((FILE *, char *, struct group const *)); - -static int next_line; - -/* Print the edit-script SCRIPT as a merged #ifdef file. */ - -void -print_ifdef_script (script) - struct change *script; -{ - next_line = - files[0].prefix_lines; - print_script (script, find_change, print_ifdef_hunk); - if (next_line < files[0].valid_lines) - { - begin_output (); - format_ifdef (group_format[UNCHANGED], next_line, files[0].valid_lines, - next_line - files[0].valid_lines + files[1].valid_lines, - files[1].valid_lines); - } -} - -/* Print a hunk of an ifdef diff. - This is a contiguous portion of a complete edit script, - describing changes in consecutive lines. */ - -static void -print_ifdef_hunk (hunk) - struct change *hunk; -{ - int first0, last0, first1, last1, deletes, inserts; - char *format; - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts); - if (inserts) - format = deletes ? group_format[CHANGED] : group_format[NEW]; - else if (deletes) - format = group_format[OLD]; - else - return; - - begin_output (); - - /* Print lines up to this change. */ - if (next_line < first0) - format_ifdef (group_format[UNCHANGED], next_line, first0, - next_line - first0 + first1, first1); - - /* Print this change. */ - next_line = last0 + 1; - format_ifdef (format, first0, next_line, first1, last1 + 1); -} - -/* Print a set of lines according to FORMAT. - Lines BEG0 up to END0 are from the first file; - lines BEG1 up to END1 are from the second file. */ - -static void -format_ifdef (format, beg0, end0, beg1, end1) - char *format; - int beg0, end0, beg1, end1; -{ - struct group groups[2]; - - groups[0].file = &files[0]; - groups[0].from = beg0; - groups[0].upto = end0; - groups[1].file = &files[1]; - groups[1].from = beg1; - groups[1].upto = end1; - format_group (outfile, format, '\0', groups); -} - -/* Print to file OUT a set of lines according to FORMAT. - The format ends at the first free instance of ENDCHAR. - Yield the address of the terminating character. - GROUPS specifies which lines to print. - If OUT is zero, do not actually print anything; just scan the format. */ - -static char * -format_group (out, format, endchar, groups) - register FILE *out; - char *format; - int endchar; - struct group const *groups; -{ - register char c; - register char *f = format; - - while ((c = *f) != endchar && c != 0) - { - f++; - if (c == '%') - { - char *spec = f; - switch ((c = *f++)) - { - case '%': - break; - - case '(': - /* Print if-then-else format e.g. `%(n=1?thenpart:elsepart)'. */ - { - int i, value[2]; - FILE *thenout, *elseout; - - for (i = 0; i < 2; i++) - { - unsigned char f0 = f[0]; - if (ISDIGIT (f0)) - { - value[i] = atoi (f); - while (ISDIGIT ((unsigned char) *++f)) - continue; - } - else - { - value[i] = groups_letter_value (groups, f0); - if (value[i] < 0) - goto bad_format; - f++; - } - if (*f++ != "=?"[i]) - goto bad_format; - } - if (value[0] == value[1]) - thenout = out, elseout = 0; - else - thenout = 0, elseout = out; - f = format_group (thenout, f, ':', groups); - if (*f) - { - f = format_group (elseout, f + 1, ')', groups); - if (*f) - f++; - } - } - continue; - - case '<': - /* Print lines deleted from first file. */ - print_ifdef_lines (out, line_format[OLD], &groups[0]); - continue; - - case '=': - /* Print common lines. */ - print_ifdef_lines (out, line_format[UNCHANGED], &groups[0]); - continue; - - case '>': - /* Print lines inserted from second file. */ - print_ifdef_lines (out, line_format[NEW], &groups[1]); - continue; - - default: - { - int value; - char *speclim; - - f = scan_printf_spec (spec); - if (!f) - goto bad_format; - speclim = f; - c = *f++; - switch (c) - { - case '\'': - f = scan_char_literal (f, &value); - if (!f) - goto bad_format; - break; - - default: - value = groups_letter_value (groups, c); - if (value < 0) - goto bad_format; - break; - } - if (out) - { - /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */ - *speclim = 0; - fprintf (out, spec - 1, value); - /* Undo the temporary replacement. */ - *speclim = c; - } - } - continue; - - bad_format: - c = '%'; - f = spec; - break; - } - } - if (out) - putc (c, out); - } - return f; -} - -/* For the line group pair G, return the number corresponding to LETTER. - Return -1 if LETTER is not a group format letter. */ -static int -groups_letter_value (g, letter) - struct group const *g; - int letter; -{ - if (ISUPPER (letter)) - { - g++; - letter = tolower (letter); - } - switch (letter) - { - case 'e': return translate_line_number (g->file, g->from) - 1; - case 'f': return translate_line_number (g->file, g->from); - case 'l': return translate_line_number (g->file, g->upto) - 1; - case 'm': return translate_line_number (g->file, g->upto); - case 'n': return g->upto - g->from; - default: return -1; - } -} - -/* Print to file OUT, using FORMAT to print the line group GROUP. - But do nothing if OUT is zero. */ -static void -print_ifdef_lines (out, format, group) - register FILE *out; - char *format; - struct group const *group; -{ - struct file_data const *file = group->file; - char const * const *linbuf = file->linbuf; - int from = group->from, upto = group->upto; - - if (!out) - return; - - /* If possible, use a single fwrite; it's faster. */ - if (!tab_expand_flag && format[0] == '%') - { - if (format[1] == 'l' && format[2] == '\n' && !format[3]) - { - fwrite (linbuf[from], sizeof (char), - linbuf[upto] + (linbuf[upto][-1] != '\n') - linbuf[from], - out); - return; - } - if (format[1] == 'L' && !format[2]) - { - fwrite (linbuf[from], sizeof (char), - linbuf[upto] - linbuf[from], out); - return; - } - } - - for (; from < upto; from++) - { - register char c; - register char *f = format; - - while ((c = *f++) != 0) - { - if (c == '%') - { - char *spec = f; - switch ((c = *f++)) - { - case '%': - break; - - case 'l': - output_1_line (linbuf[from], - linbuf[from + 1] - - (linbuf[from + 1][-1] == '\n'), 0, 0); - continue; - - case 'L': - output_1_line (linbuf[from], linbuf[from + 1], 0, 0); - continue; - - default: - { - int value; - char *speclim; - - f = scan_printf_spec (spec); - if (!f) - goto bad_format; - speclim = f; - c = *f++; - switch (c) - { - case '\'': - f = scan_char_literal (f, &value); - if (!f) - goto bad_format; - break; - - case 'n': - value = translate_line_number (file, from); - break; - - default: - goto bad_format; - } - /* Temporarily replace e.g. "%3dnx" with "%3d\0x". */ - *speclim = 0; - fprintf (out, spec - 1, value); - /* Undo the temporary replacement. */ - *speclim = c; - } - continue; - - bad_format: - c = '%'; - f = spec; - break; - } - } - putc (c, out); - } - } -} - -/* Scan the character literal represented in the string LIT; LIT points just - after the initial apostrophe. Put the literal's value into *INTPTR. - Yield the address of the first character after the closing apostrophe, - or zero if the literal is ill-formed. */ -static char * -scan_char_literal (lit, intptr) - char *lit; - int *intptr; -{ - register char *p = lit; - int value, digits; - char c = *p++; - - switch (c) - { - case 0: - case '\'': - return 0; - - case '\\': - value = 0; - while ((c = *p++) != '\'') - { - unsigned digit = c - '0'; - if (8 <= digit) - return 0; - value = 8 * value + digit; - } - digits = p - lit - 2; - if (! (1 <= digits && digits <= 3)) - return 0; - break; - - default: - value = c; - if (*p++ != '\'') - return 0; - break; - } - *intptr = value; - return p; -} - -/* Scan optional printf-style SPEC of the form `-*[0-9]*(.[0-9]*)?[cdoxX]'. - Return the address of the character following SPEC, or zero if failure. */ -static char * -scan_printf_spec (spec) - register char *spec; -{ - register unsigned char c; - - while ((c = *spec++) == '-') - continue; - while (ISDIGIT (c)) - c = *spec++; - if (c == '.') - while (ISDIGIT (c = *spec++)) - continue; - switch (c) - { - case 'c': case 'd': case 'o': case 'x': case 'X': - return spec; - - default: - return 0; - } -} diff --git a/gnu/usr.bin/diff/io.c b/gnu/usr.bin/diff/io.c deleted file mode 100644 index 660591551091..000000000000 --- a/gnu/usr.bin/diff/io.c +++ /dev/null @@ -1,714 +0,0 @@ -/* File I/O for GNU DIFF. - Copyright (C) 1988, 1989, 1992, 1993, 1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "diff.h" - -/* Rotate a value n bits to the left. */ -#define UINT_BIT (sizeof (unsigned) * CHAR_BIT) -#define ROL(v, n) ((v) << (n) | (v) >> (UINT_BIT - (n))) - -/* Given a hash value and a new character, return a new hash value. */ -#define HASH(h, c) ((c) + ROL (h, 7)) - -/* Guess remaining number of lines from number N of lines so far, - size S so far, and total size T. */ -#define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5) - -/* Type used for fast prefix comparison in find_identical_ends. */ -#ifndef word -#define word int -#endif - -/* Lines are put into equivalence classes (of lines that match in line_cmp). - Each equivalence class is represented by one of these structures, - but only while the classes are being computed. - Afterward, each class is represented by a number. */ -struct equivclass -{ - int next; /* Next item in this bucket. */ - unsigned hash; /* Hash of lines in this class. */ - char const *line; /* A line that fits this class. */ - size_t length; /* That line's length, not counting its newline. */ -}; - -/* Hash-table: array of buckets, each being a chain of equivalence classes. - buckets[-1] is reserved for incomplete lines. */ -static int *buckets; - -/* Number of buckets in the hash table array, not counting buckets[-1]. */ -static int nbuckets; - -/* Array in which the equivalence classes are allocated. - The bucket-chains go through the elements in this array. - The number of an equivalence class is its index in this array. */ -static struct equivclass *equivs; - -/* Index of first free element in the array `equivs'. */ -static int equivs_index; - -/* Number of elements allocated in the array `equivs'. */ -static int equivs_alloc; - -static void find_and_hash_each_line PARAMS((struct file_data *)); -static void find_identical_ends PARAMS((struct file_data[])); -static void prepare_text_end PARAMS((struct file_data *)); - -/* Check for binary files and compare them for exact identity. */ - -/* Return 1 if BUF contains a non text character. - SIZE is the number of characters in BUF. */ - -#define binary_file_p(buf, size) (memchr (buf, '\0', size) != 0) - -/* Get ready to read the current file. - Return nonzero if SKIP_TEST is zero, - and if it appears to be a binary file. */ - -int -sip (current, skip_test) - struct file_data *current; - int skip_test; -{ - /* If we have a nonexistent file at this stage, treat it as empty. */ - if (current->desc < 0) - { - /* Leave room for a sentinel. */ - current->bufsize = sizeof (word); - current->buffer = xmalloc (current->bufsize); - } - else - { - current->bufsize = STAT_BLOCKSIZE (current->stat); - current->buffer = xmalloc (current->bufsize); - - if (! skip_test) - { - /* Check first part of file to see if it's a binary file. */ -#if HAVE_SETMODE - int oldmode = setmode (current->desc, O_BINARY); -#endif - size_t n = read (current->desc, current->buffer, current->bufsize); - if (n == -1) - pfatal_with_name (current->name); - current->buffered_chars = n; -#if HAVE_SETMODE - if (oldmode != O_BINARY) - { - if (lseek (current->desc, - (off_t) n, SEEK_CUR) == -1) - pfatal_with_name (current->name); - setmode (current->desc, oldmode); - current->buffered_chars = 0; - } -#endif - return binary_file_p (current->buffer, n); - } - } - - current->buffered_chars = 0; - return 0; -} - -/* Slurp the rest of the current file completely into memory. */ - -void -slurp (current) - struct file_data *current; -{ - size_t cc; - - if (current->desc < 0) - /* The file is nonexistent. */ - ; - else if (S_ISREG (current->stat.st_mode)) - { - /* It's a regular file; slurp in the rest all at once. */ - - /* Get the size out of the stat block. - Allocate enough room for appended newline and sentinel. */ - cc = current->stat.st_size + 1 + sizeof (word); - if (current->bufsize < cc) - { - current->bufsize = cc; - current->buffer = xrealloc (current->buffer, cc); - } - - if (current->buffered_chars < current->stat.st_size) - { - cc = read (current->desc, - current->buffer + current->buffered_chars, - current->stat.st_size - current->buffered_chars); - if (cc == -1) - pfatal_with_name (current->name); - current->buffered_chars += cc; - } - } - /* It's not a regular file; read it, growing the buffer as needed. */ - else if (always_text_flag || current->buffered_chars != 0) - { - for (;;) - { - if (current->buffered_chars == current->bufsize) - { - current->bufsize = current->bufsize * 2; - current->buffer = xrealloc (current->buffer, current->bufsize); - } - cc = read (current->desc, - current->buffer + current->buffered_chars, - current->bufsize - current->buffered_chars); - if (cc == 0) - break; - if (cc == -1) - pfatal_with_name (current->name); - current->buffered_chars += cc; - } - /* Allocate just enough room for appended newline and sentinel. */ - current->bufsize = current->buffered_chars + 1 + sizeof (word); - current->buffer = xrealloc (current->buffer, current->bufsize); - } -} - -/* Split the file into lines, simultaneously computing the equivalence class for - each line. */ - -static void -find_and_hash_each_line (current) - struct file_data *current; -{ - unsigned h; - unsigned char const *p = (unsigned char const *) current->prefix_end; - unsigned char c; - int i, *bucket; - size_t length; - - /* Cache often-used quantities in local variables to help the compiler. */ - char const **linbuf = current->linbuf; - int alloc_lines = current->alloc_lines; - int line = 0; - int linbuf_base = current->linbuf_base; - int *cureqs = (int *) xmalloc (alloc_lines * sizeof (int)); - struct equivclass *eqs = equivs; - int eqs_index = equivs_index; - int eqs_alloc = equivs_alloc; - char const *suffix_begin = current->suffix_begin; - char const *bufend = current->buffer + current->buffered_chars; - int use_line_cmp = ignore_some_line_changes; - - while ((char const *) p < suffix_begin) - { - char const *ip = (char const *) p; - - /* Compute the equivalence class for this line. */ - - h = 0; - - /* Hash this line until we find a newline. */ - if (ignore_case_flag) - { - if (ignore_all_space_flag) - while ((c = *p++) != '\n') - { - if (! ISSPACE (c)) - h = HASH (h, ISUPPER (c) ? tolower (c) : c); - } - else if (ignore_space_change_flag) - while ((c = *p++) != '\n') - { - if (ISSPACE (c)) - { - for (;;) - { - c = *p++; - if (!ISSPACE (c)) - break; - if (c == '\n') - goto hashing_done; - } - h = HASH (h, ' '); - } - /* C is now the first non-space. */ - h = HASH (h, ISUPPER (c) ? tolower (c) : c); - } - else - while ((c = *p++) != '\n') - h = HASH (h, ISUPPER (c) ? tolower (c) : c); - } - else - { - if (ignore_all_space_flag) - while ((c = *p++) != '\n') - { - if (! ISSPACE (c)) - h = HASH (h, c); - } - else if (ignore_space_change_flag) - while ((c = *p++) != '\n') - { - if (ISSPACE (c)) - { - for (;;) - { - c = *p++; - if (!ISSPACE (c)) - break; - if (c == '\n') - goto hashing_done; - } - h = HASH (h, ' '); - } - /* C is now the first non-space. */ - h = HASH (h, c); - } - else - while ((c = *p++) != '\n') - h = HASH (h, c); - } - hashing_done:; - - bucket = &buckets[h % nbuckets]; - length = (char const *) p - ip - 1; - - if ((char const *) p == bufend - && current->missing_newline - && ROBUST_OUTPUT_STYLE (output_style)) - { - /* This line is incomplete. If this is significant, - put the line into bucket[-1]. */ - if (! (ignore_space_change_flag | ignore_all_space_flag)) - bucket = &buckets[-1]; - - /* Omit the inserted newline when computing linbuf later. */ - p--; - bufend = suffix_begin = (char const *) p; - } - - for (i = *bucket; ; i = eqs[i].next) - if (!i) - { - /* Create a new equivalence class in this bucket. */ - i = eqs_index++; - if (i == eqs_alloc) - eqs = (struct equivclass *) - xrealloc (eqs, (eqs_alloc*=2) * sizeof(*eqs)); - eqs[i].next = *bucket; - eqs[i].hash = h; - eqs[i].line = ip; - eqs[i].length = length; - *bucket = i; - break; - } - else if (eqs[i].hash == h) - { - char const *eqline = eqs[i].line; - - /* Reuse existing equivalence class if the lines are identical. - This detects the common case of exact identity - faster than complete comparison would. */ - if (eqs[i].length == length && memcmp (eqline, ip, length) == 0) - break; - - /* Reuse existing class if line_cmp reports the lines equal. */ - if (use_line_cmp && line_cmp (eqline, ip) == 0) - break; - } - - /* Maybe increase the size of the line table. */ - if (line == alloc_lines) - { - /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */ - alloc_lines = 2 * alloc_lines - linbuf_base; - cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs)); - linbuf = (char const **) xrealloc (linbuf + linbuf_base, - (alloc_lines - linbuf_base) - * sizeof (*linbuf)) - - linbuf_base; - } - linbuf[line] = ip; - cureqs[line] = i; - ++line; - } - - current->buffered_lines = line; - - for (i = 0; ; i++) - { - /* Record the line start for lines in the suffix that we care about. - Record one more line start than lines, - so that we can compute the length of any buffered line. */ - if (line == alloc_lines) - { - /* Double (alloc_lines - linbuf_base) by adding to alloc_lines. */ - alloc_lines = 2 * alloc_lines - linbuf_base; - linbuf = (char const **) xrealloc (linbuf + linbuf_base, - (alloc_lines - linbuf_base) - * sizeof (*linbuf)) - - linbuf_base; - } - linbuf[line] = (char const *) p; - - if ((char const *) p == bufend) - break; - - if (context <= i && no_diff_means_no_output) - break; - - line++; - - while (*p++ != '\n') - ; - } - - /* Done with cache in local variables. */ - current->linbuf = linbuf; - current->valid_lines = line; - current->alloc_lines = alloc_lines; - current->equivs = cureqs; - equivs = eqs; - equivs_alloc = eqs_alloc; - equivs_index = eqs_index; -} - -/* Prepare the end of the text. Make sure it's initialized. - Make sure text ends in a newline, - but remember that we had to add one. */ - -static void -prepare_text_end (current) - struct file_data *current; -{ - size_t buffered_chars = current->buffered_chars; - char *p = current->buffer; - - if (buffered_chars == 0 || p[buffered_chars - 1] == '\n') - current->missing_newline = 0; - else - { - p[buffered_chars++] = '\n'; - current->buffered_chars = buffered_chars; - current->missing_newline = 1; - } - - /* Don't use uninitialized storage when planting or using sentinels. */ - if (p) - bzero (p + buffered_chars, sizeof (word)); -} - -/* Given a vector of two file_data objects, find the identical - prefixes and suffixes of each object. */ - -static void -find_identical_ends (filevec) - struct file_data filevec[]; -{ - word *w0, *w1; - char *p0, *p1, *buffer0, *buffer1; - char const *end0, *beg0; - char const **linbuf0, **linbuf1; - int i, lines; - size_t n0, n1, tem; - int alloc_lines0, alloc_lines1; - int buffered_prefix, prefix_count, prefix_mask; - - slurp (&filevec[0]); - if (filevec[0].desc != filevec[1].desc) - slurp (&filevec[1]); - else - { - filevec[1].buffer = filevec[0].buffer; - filevec[1].bufsize = filevec[0].bufsize; - filevec[1].buffered_chars = filevec[0].buffered_chars; - } - for (i = 0; i < 2; i++) - prepare_text_end (&filevec[i]); - - /* Find identical prefix. */ - - p0 = buffer0 = filevec[0].buffer; - p1 = buffer1 = filevec[1].buffer; - - n0 = filevec[0].buffered_chars; - n1 = filevec[1].buffered_chars; - - if (p0 == p1) - /* The buffers are the same; sentinels won't work. */ - p0 = p1 += n1; - else - { - /* Insert end sentinels, in this case characters that are guaranteed - to make the equality test false, and thus terminate the loop. */ - - if (n0 < n1) - p0[n0] = ~p1[n0]; - else - p1[n1] = ~p0[n1]; - - /* Loop until first mismatch, or to the sentinel characters. */ - - /* Compare a word at a time for speed. */ - w0 = (word *) p0; - w1 = (word *) p1; - while (*w0++ == *w1++) - ; - --w0, --w1; - - /* Do the last few bytes of comparison a byte at a time. */ - p0 = (char *) w0; - p1 = (char *) w1; - while (*p0++ == *p1++) - ; - --p0, --p1; - - /* Don't mistakenly count missing newline as part of prefix. */ - if (ROBUST_OUTPUT_STYLE (output_style) - && (buffer0 + n0 - filevec[0].missing_newline < p0) - != - (buffer1 + n1 - filevec[1].missing_newline < p1)) - --p0, --p1; - } - - /* Now P0 and P1 point at the first nonmatching characters. */ - - /* Skip back to last line-beginning in the prefix, - and then discard up to HORIZON_LINES lines from the prefix. */ - i = horizon_lines; - while (p0 != buffer0 && (p0[-1] != '\n' || i--)) - --p0, --p1; - - /* Record the prefix. */ - filevec[0].prefix_end = p0; - filevec[1].prefix_end = p1; - - /* Find identical suffix. */ - - /* P0 and P1 point beyond the last chars not yet compared. */ - p0 = buffer0 + n0; - p1 = buffer1 + n1; - - if (! ROBUST_OUTPUT_STYLE (output_style) - || filevec[0].missing_newline == filevec[1].missing_newline) - { - end0 = p0; /* Addr of last char in file 0. */ - - /* Get value of P0 at which we should stop scanning backward: - this is when either P0 or P1 points just past the last char - of the identical prefix. */ - beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1); - - /* Scan back until chars don't match or we reach that point. */ - while (p0 != beg0) - if (*--p0 != *--p1) - { - /* Point at the first char of the matching suffix. */ - ++p0, ++p1; - beg0 = p0; - break; - } - - /* Are we at a line-beginning in both files? If not, add the rest of - this line to the main body. Discard up to HORIZON_LINES lines from - the identical suffix. Also, discard one extra line, - because shift_boundaries may need it. */ - i = horizon_lines + !((buffer0 == p0 || p0[-1] == '\n') - && - (buffer1 == p1 || p1[-1] == '\n')); - while (i-- && p0 != end0) - while (*p0++ != '\n') - ; - - p1 += p0 - beg0; - } - - /* Record the suffix. */ - filevec[0].suffix_begin = p0; - filevec[1].suffix_begin = p1; - - /* Calculate number of lines of prefix to save. - - prefix_count == 0 means save the whole prefix; - we need this with for options like -D that output the whole file. - We also need it for options like -F that output some preceding line; - at least we will need to find the last few lines, - but since we don't know how many, it's easiest to find them all. - - Otherwise, prefix_count != 0. Save just prefix_count lines at start - of the line buffer; they'll be moved to the proper location later. - Handle 1 more line than the context says (because we count 1 too many), - rounded up to the next power of 2 to speed index computation. */ - - if (no_diff_means_no_output && ! function_regexp_list) - { - for (prefix_count = 1; prefix_count < context + 1; prefix_count *= 2) - ; - prefix_mask = prefix_count - 1; - alloc_lines0 - = prefix_count - + GUESS_LINES (0, 0, p0 - filevec[0].prefix_end) - + context; - } - else - { - prefix_count = 0; - prefix_mask = ~0; - alloc_lines0 = GUESS_LINES (0, 0, n0); - } - - lines = 0; - linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0)); - - /* If the prefix is needed, find the prefix lines. */ - if (! (no_diff_means_no_output - && filevec[0].prefix_end == p0 - && filevec[1].prefix_end == p1)) - { - p0 = buffer0; - end0 = filevec[0].prefix_end; - while (p0 != end0) - { - int l = lines++ & prefix_mask; - if (l == alloc_lines0) - linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2) - * sizeof(*linbuf0)); - linbuf0[l] = p0; - while (*p0++ != '\n') - ; - } - } - buffered_prefix = prefix_count && context < lines ? context : lines; - - /* Allocate line buffer 1. */ - tem = prefix_count ? filevec[1].suffix_begin - buffer1 : n1; - - alloc_lines1 - = (buffered_prefix - + GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem) - + context); - linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1)); - - if (buffered_prefix != lines) - { - /* Rotate prefix lines to proper location. */ - for (i = 0; i < buffered_prefix; i++) - linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask]; - for (i = 0; i < buffered_prefix; i++) - linbuf0[i] = linbuf1[i]; - } - - /* Initialize line buffer 1 from line buffer 0. */ - for (i = 0; i < buffered_prefix; i++) - linbuf1[i] = linbuf0[i] - buffer0 + buffer1; - - /* Record the line buffer, adjusted so that - linbuf*[0] points at the first differing line. */ - filevec[0].linbuf = linbuf0 + buffered_prefix; - filevec[1].linbuf = linbuf1 + buffered_prefix; - filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix; - filevec[0].alloc_lines = alloc_lines0 - buffered_prefix; - filevec[1].alloc_lines = alloc_lines1 - buffered_prefix; - filevec[0].prefix_lines = filevec[1].prefix_lines = lines; -} - -/* Largest primes less than some power of two, for nbuckets. Values range - from useful to preposterous. If one of these numbers isn't prime - after all, don't blame it on me, blame it on primes (6) . . . */ -static int const primes[] = -{ - 509, - 1021, - 2039, - 4093, - 8191, - 16381, - 32749, -#if 32767 < INT_MAX - 65521, - 131071, - 262139, - 524287, - 1048573, - 2097143, - 4194301, - 8388593, - 16777213, - 33554393, - 67108859, /* Preposterously large . . . */ - 134217689, - 268435399, - 536870909, - 1073741789, - 2147483647, -#endif - 0 -}; - -/* Given a vector of two file_data objects, read the file associated - with each one, and build the table of equivalence classes. - Return 1 if either file appears to be a binary file. - If PRETEND_BINARY is nonzero, pretend they are binary regardless. */ - -int -read_files (filevec, pretend_binary) - struct file_data filevec[]; - int pretend_binary; -{ - int i; - int skip_test = always_text_flag | pretend_binary; - int appears_binary = pretend_binary | sip (&filevec[0], skip_test); - - if (filevec[0].desc != filevec[1].desc) - appears_binary |= sip (&filevec[1], skip_test | appears_binary); - else - { - filevec[1].buffer = filevec[0].buffer; - filevec[1].bufsize = filevec[0].bufsize; - filevec[1].buffered_chars = filevec[0].buffered_chars; - } - if (appears_binary) - { -#if HAVE_SETMODE - setmode (filevec[0].desc, O_BINARY); - setmode (filevec[1].desc, O_BINARY); -#endif - return 1; - } - - find_identical_ends (filevec); - - equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1; - equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass)); - /* Equivalence class 0 is permanently safe for lines that were not - hashed. Real equivalence classes start at 1. */ - equivs_index = 1; - - for (i = 0; primes[i] < equivs_alloc / 3; i++) - if (! primes[i]) - abort (); - nbuckets = primes[i]; - - buckets = (int *) xmalloc ((nbuckets + 1) * sizeof (*buckets)); - bzero (buckets++, (nbuckets + 1) * sizeof (*buckets)); - - for (i = 0; i < 2; i++) - find_and_hash_each_line (&filevec[i]); - - filevec[0].equiv_max = filevec[1].equiv_max = equivs_index; - - free (equivs); - free (buckets - 1); - - return 0; -} diff --git a/gnu/usr.bin/diff/normal.c b/gnu/usr.bin/diff/normal.c deleted file mode 100644 index 4d9e23cb72a0..000000000000 --- a/gnu/usr.bin/diff/normal.c +++ /dev/null @@ -1,71 +0,0 @@ -/* Normal-format output routines for GNU DIFF. - Copyright (C) 1988, 1989, 1993 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -#include "diff.h" - -static void print_normal_hunk PARAMS((struct change *)); - -/* Print the edit-script SCRIPT as a normal diff. - INF points to an array of descriptions of the two files. */ - -void -print_normal_script (script) - struct change *script; -{ - print_script (script, find_change, print_normal_hunk); -} - -/* Print a hunk of a normal diff. - This is a contiguous portion of a complete edit script, - describing changes in consecutive lines. */ - -static void -print_normal_hunk (hunk) - struct change *hunk; -{ - int first0, last0, first1, last1, deletes, inserts; - register int i; - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts); - if (!deletes && !inserts) - return; - - begin_output (); - - /* Print out the line number header for this hunk */ - print_number_range (',', &files[0], first0, last0); - fprintf (outfile, "%c", change_letter (inserts, deletes)); - print_number_range (',', &files[1], first1, last1); - fprintf (outfile, "\n"); - - /* Print the lines that the first file has. */ - if (deletes) - for (i = first0; i <= last0; i++) - print_1_line ("<", &files[0].linbuf[i]); - - if (inserts && deletes) - fprintf (outfile, "---\n"); - - /* Print the lines that the second file has. */ - if (inserts) - for (i = first1; i <= last1; i++) - print_1_line (">", &files[1].linbuf[i]); -} diff --git a/gnu/usr.bin/diff/regex.c b/gnu/usr.bin/diff/regex.c deleted file mode 100644 index 5d8c4566f5ff..000000000000 --- a/gnu/usr.bin/diff/regex.c +++ /dev/null @@ -1,5248 +0,0 @@ -/* Extended regular expression matching and search library, - version 0.12. - (Implements POSIX draft P10003.2/D11.2, except for - internationalization features.) - - Copyright (C) 1993, 1994 Free Software Foundation, Inc. - - This program 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. - - This program 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; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* AIX requires this to be the first thing in the file. */ -#if defined (_AIX) && !defined (REGEX_MALLOC) - #pragma alloca -#endif - -#define _GNU_SOURCE - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* We need this for `regex.h', and perhaps for the Emacs include files. */ -#include - -/* The `emacs' switch turns on certain matching commands - that make sense only in Emacs. */ -#ifdef emacs - -#include "lisp.h" -#include "buffer.h" -#include "syntax.h" - -/* Emacs uses `NULL' as a predicate. */ -#undef NULL - -#else /* not emacs */ - -#ifdef STDC_HEADERS -#include -#else -char *malloc (); -char *realloc (); -#endif - - -/* We used to test for `BSTRING' here, but only GCC and Emacs define - `BSTRING', as far as I know, and neither of them use this code. */ -#ifndef INHIBIT_STRING_HEADER -#if HAVE_STRING_H || STDC_HEADERS -#include -#ifndef bcmp -#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) -#endif -#ifndef bcopy -#define bcopy(s, d, n) memcpy ((d), (s), (n)) -#endif -#ifndef bzero -#define bzero(s, n) memset ((s), 0, (n)) -#endif -#else -#include -#endif -#endif - -/* Define the syntax stuff for \<, \>, etc. */ - -/* This must be nonzero for the wordchar and notwordchar pattern - commands in re_match_2. */ -#ifndef Sword -#define Sword 1 -#endif - -#ifdef SYNTAX_TABLE - -extern char *re_syntax_table; - -#else /* not SYNTAX_TABLE */ - -/* How many characters in the character set. */ -#define CHAR_SET_SIZE 256 - -static char re_syntax_table[CHAR_SET_SIZE]; - -static void -init_syntax_once () -{ - register int c; - static int done = 0; - - if (done) - return; - - bzero (re_syntax_table, sizeof re_syntax_table); - - for (c = 'a'; c <= 'z'; c++) - re_syntax_table[c] = Sword; - - for (c = 'A'; c <= 'Z'; c++) - re_syntax_table[c] = Sword; - - for (c = '0'; c <= '9'; c++) - re_syntax_table[c] = Sword; - - re_syntax_table['_'] = Sword; - - done = 1; -} - -#endif /* not SYNTAX_TABLE */ - -#define SYNTAX(c) re_syntax_table[c] - -#endif /* not emacs */ - -/* Get the interface, including the syntax bits. */ -#include "regex.h" - -/* isalpha etc. are used for the character classes. */ -#include - -/* Jim Meyering writes: - - "... Some ctype macros are valid only for character codes that - isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when - using /bin/cc or gcc but without giving an ansi option). So, all - ctype uses should be through macros like ISPRINT... If - STDC_HEADERS is defined, then autoconf has verified that the ctype - macros don't need to be guarded with references to isascii. ... - Defining isascii to 1 should let any compiler worth its salt - eliminate the && through constant folding." */ - -#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) -#define ISASCII(c) 1 -#else -#define ISASCII(c) isascii(c) -#endif - -#ifdef isblank -#define ISBLANK(c) (ISASCII (c) && isblank (c)) -#else -#define ISBLANK(c) ((c) == ' ' || (c) == '\t') -#endif -#ifdef isgraph -#define ISGRAPH(c) (ISASCII (c) && isgraph (c)) -#else -#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) -#endif - -#define ISPRINT(c) (ISASCII (c) && isprint (c)) -#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) -#define ISALNUM(c) (ISASCII (c) && isalnum (c)) -#define ISALPHA(c) (ISASCII (c) && isalpha (c)) -#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) -#define ISLOWER(c) (ISASCII (c) && islower (c)) -#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) -#define ISSPACE(c) (ISASCII (c) && isspace (c)) -#define ISUPPER(c) (ISASCII (c) && isupper (c)) -#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) - -#ifndef NULL -#define NULL 0 -#endif - -/* We remove any previous definition of `SIGN_EXTEND_CHAR', - since ours (we hope) works properly with all combinations of - machines, compilers, `char' and `unsigned char' argument types. - (Per Bothner suggested the basic approach.) */ -#undef SIGN_EXTEND_CHAR -#if __STDC__ -#define SIGN_EXTEND_CHAR(c) ((signed char) (c)) -#else /* not __STDC__ */ -/* As in Harbison and Steele. */ -#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) -#endif - -/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we - use `alloca' instead of `malloc'. This is because using malloc in - re_search* or re_match* could cause memory leaks when C-g is used in - Emacs; also, malloc is slower and causes storage fragmentation. On - the other hand, malloc is more portable, and easier to debug. - - Because we sometimes use alloca, some routines have to be macros, - not functions -- `alloca'-allocated space disappears at the end of the - function it is called in. */ - -#ifdef REGEX_MALLOC - -#define REGEX_ALLOCATE malloc -#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) - -#else /* not REGEX_MALLOC */ - -/* Emacs already defines alloca, sometimes. */ -#ifndef alloca - -/* Make alloca work the best possible way. */ -#ifdef __GNUC__ -#define alloca __builtin_alloca -#else /* not __GNUC__ */ -#if HAVE_ALLOCA_H -#include -#else /* not __GNUC__ or HAVE_ALLOCA_H */ -#ifndef _AIX /* Already did AIX, up at the top. */ -char *alloca (); -#endif /* not _AIX */ -#endif /* not HAVE_ALLOCA_H */ -#endif /* not __GNUC__ */ - -#endif /* not alloca */ - -#define REGEX_ALLOCATE alloca - -/* Assumes a `char *destination' variable. */ -#define REGEX_REALLOCATE(source, osize, nsize) \ - (destination = (char *) alloca (nsize), \ - bcopy (source, destination, osize), \ - destination) - -#endif /* not REGEX_MALLOC */ - - -/* True if `size1' is non-NULL and PTR is pointing anywhere inside - `string1' or just past its end. This works if PTR is NULL, which is - a good thing. */ -#define FIRST_STRING_P(ptr) \ - (size1 && string1 <= (ptr) && (ptr) <= string1 + size1) - -/* (Re)Allocate N items of type T using malloc, or fail. */ -#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) -#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) -#define RETALLOC_IF(addr, n, t) \ - if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) -#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) - -#define BYTEWIDTH 8 /* In bits. */ - -#define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) - -#undef MAX -#undef MIN -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -typedef char boolean; -#define false 0 -#define true 1 - -static int re_match_2_internal (); - -/* These are the command codes that appear in compiled regular - expressions. Some opcodes are followed by argument bytes. A - command code can specify any interpretation whatsoever for its - arguments. Zero bytes may appear in the compiled regular expression. - - The value of `exactn' is needed in search.c (search_buffer) in Emacs. - So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of - `exactn' we use here must also be 1. */ - -typedef enum -{ - no_op = 0, - - /* Followed by one byte giving n, then by n literal bytes. */ - exactn = 1, - - /* Matches any (more or less) character. */ - anychar, - - /* Matches any one char belonging to specified set. First - following byte is number of bitmap bytes. Then come bytes - for a bitmap saying which chars are in. Bits in each byte - are ordered low-bit-first. A character is in the set if its - bit is 1. A character too large to have a bit in the map is - automatically not in the set. */ - charset, - - /* Same parameters as charset, but match any character that is - not one of those specified. */ - charset_not, - - /* Start remembering the text that is matched, for storing in a - register. Followed by one byte with the register number, in - the range 0 to one less than the pattern buffer's re_nsub - field. Then followed by one byte with the number of groups - inner to this one. (This last has to be part of the - start_memory only because we need it in the on_failure_jump - of re_match_2.) */ - start_memory, - - /* Stop remembering the text that is matched and store it in a - memory register. Followed by one byte with the register - number, in the range 0 to one less than `re_nsub' in the - pattern buffer, and one byte with the number of inner groups, - just like `start_memory'. (We need the number of inner - groups here because we don't have any easy way of finding the - corresponding start_memory when we're at a stop_memory.) */ - stop_memory, - - /* Match a duplicate of something remembered. Followed by one - byte containing the register number. */ - duplicate, - - /* Fail unless at beginning of line. */ - begline, - - /* Fail unless at end of line. */ - endline, - - /* Succeeds if at beginning of buffer (if emacs) or at beginning - of string to be matched (if not). */ - begbuf, - - /* Analogously, for end of buffer/string. */ - endbuf, - - /* Followed by two byte relative address to which to jump. */ - jump, - - /* Same as jump, but marks the end of an alternative. */ - jump_past_alt, - - /* Followed by two-byte relative address of place to resume at - in case of failure. */ - on_failure_jump, - - /* Like on_failure_jump, but pushes a placeholder instead of the - current string position when executed. */ - on_failure_keep_string_jump, - - /* Throw away latest failure point and then jump to following - two-byte relative address. */ - pop_failure_jump, - - /* Change to pop_failure_jump if know won't have to backtrack to - match; otherwise change to jump. This is used to jump - back to the beginning of a repeat. If what follows this jump - clearly won't match what the repeat does, such that we can be - sure that there is no use backtracking out of repetitions - already matched, then we change it to a pop_failure_jump. - Followed by two-byte address. */ - maybe_pop_jump, - - /* Jump to following two-byte address, and push a dummy failure - point. This failure point will be thrown away if an attempt - is made to use it for a failure. A `+' construct makes this - before the first repeat. Also used as an intermediary kind - of jump when compiling an alternative. */ - dummy_failure_jump, - - /* Push a dummy failure point and continue. Used at the end of - alternatives. */ - push_dummy_failure, - - /* Followed by two-byte relative address and two-byte number n. - After matching N times, jump to the address upon failure. */ - succeed_n, - - /* Followed by two-byte relative address, and two-byte number n. - Jump to the address N times, then fail. */ - jump_n, - - /* Set the following two-byte relative address to the - subsequent two-byte number. The address *includes* the two - bytes of number. */ - set_number_at, - - wordchar, /* Matches any word-constituent character. */ - notwordchar, /* Matches any char that is not a word-constituent. */ - - wordbeg, /* Succeeds if at word beginning. */ - wordend, /* Succeeds if at word end. */ - - wordbound, /* Succeeds if at a word boundary. */ - notwordbound /* Succeeds if not at a word boundary. */ - -#ifdef emacs - ,before_dot, /* Succeeds if before point. */ - at_dot, /* Succeeds if at point. */ - after_dot, /* Succeeds if after point. */ - - /* Matches any character whose syntax is specified. Followed by - a byte which contains a syntax code, e.g., Sword. */ - syntaxspec, - - /* Matches any character whose syntax is not that specified. */ - notsyntaxspec -#endif /* emacs */ -} re_opcode_t; - -/* Common operations on the compiled pattern. */ - -/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ - -#define STORE_NUMBER(destination, number) \ - do { \ - (destination)[0] = (number) & 0377; \ - (destination)[1] = (number) >> 8; \ - } while (0) - -/* Same as STORE_NUMBER, except increment DESTINATION to - the byte after where the number is stored. Therefore, DESTINATION - must be an lvalue. */ - -#define STORE_NUMBER_AND_INCR(destination, number) \ - do { \ - STORE_NUMBER (destination, number); \ - (destination) += 2; \ - } while (0) - -/* Put into DESTINATION a number stored in two contiguous bytes starting - at SOURCE. */ - -#define EXTRACT_NUMBER(destination, source) \ - do { \ - (destination) = *(source) & 0377; \ - (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ - } while (0) - -#ifdef DEBUG -static void -extract_number (dest, source) - int *dest; - unsigned char *source; -{ - int temp = SIGN_EXTEND_CHAR (*(source + 1)); - *dest = *source & 0377; - *dest += temp << 8; -} - -#ifndef EXTRACT_MACROS /* To debug the macros. */ -#undef EXTRACT_NUMBER -#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src) -#endif /* not EXTRACT_MACROS */ - -#endif /* DEBUG */ - -/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. - SOURCE must be an lvalue. */ - -#define EXTRACT_NUMBER_AND_INCR(destination, source) \ - do { \ - EXTRACT_NUMBER (destination, source); \ - (source) += 2; \ - } while (0) - -#ifdef DEBUG -static void -extract_number_and_incr (destination, source) - int *destination; - unsigned char **source; -{ - extract_number (destination, *source); - *source += 2; -} - -#ifndef EXTRACT_MACROS -#undef EXTRACT_NUMBER_AND_INCR -#define EXTRACT_NUMBER_AND_INCR(dest, src) \ - extract_number_and_incr (&dest, &src) -#endif /* not EXTRACT_MACROS */ - -#endif /* DEBUG */ - -/* If DEBUG is defined, Regex prints many voluminous messages about what - it is doing (if the variable `debug' is nonzero). If linked with the - main program in `iregex.c', you can enter patterns and strings - interactively. And if linked with the main program in `main.c' and - the other test files, you can run the already-written tests. */ - -#ifdef DEBUG - -/* We use standard I/O for debugging. */ -#include - -/* It is useful to test things that ``must'' be true when debugging. */ -#include - -static int debug = 0; - -#define DEBUG_STATEMENT(e) e -#define DEBUG_PRINT1(x) if (debug) printf (x) -#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) -#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) -#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) -#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ - if (debug) print_partial_compiled_pattern (s, e) -#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ - if (debug) print_double_string (w, s1, sz1, s2, sz2) - - -extern void printchar (); - -/* Print the fastmap in human-readable form. */ - -void -print_fastmap (fastmap) - char *fastmap; -{ - unsigned was_a_range = 0; - unsigned i = 0; - - while (i < (1 << BYTEWIDTH)) - { - if (fastmap[i++]) - { - was_a_range = 0; - printchar (i - 1); - while (i < (1 << BYTEWIDTH) && fastmap[i]) - { - was_a_range = 1; - i++; - } - if (was_a_range) - { - printf ("-"); - printchar (i - 1); - } - } - } - putchar ('\n'); -} - - -/* Print a compiled pattern string in human-readable form, starting at - the START pointer into it and ending just before the pointer END. */ - -void -print_partial_compiled_pattern (start, end) - unsigned char *start; - unsigned char *end; -{ - int mcnt, mcnt2; - unsigned char *p = start; - unsigned char *pend = end; - - if (start == NULL) - { - printf ("(null)\n"); - return; - } - - /* Loop over pattern commands. */ - while (p < pend) - { - printf ("%d:\t", p - start); - - switch ((re_opcode_t) *p++) - { - case no_op: - printf ("/no_op"); - break; - - case exactn: - mcnt = *p++; - printf ("/exactn/%d", mcnt); - do - { - putchar ('/'); - printchar (*p++); - } - while (--mcnt); - break; - - case start_memory: - mcnt = *p++; - printf ("/start_memory/%d/%d", mcnt, *p++); - break; - - case stop_memory: - mcnt = *p++; - printf ("/stop_memory/%d/%d", mcnt, *p++); - break; - - case duplicate: - printf ("/duplicate/%d", *p++); - break; - - case anychar: - printf ("/anychar"); - break; - - case charset: - case charset_not: - { - register int c, last = -100; - register int in_range = 0; - - printf ("/charset [%s", - (re_opcode_t) *(p - 1) == charset_not ? "^" : ""); - - assert (p + *p < pend); - - for (c = 0; c < 256; c++) - if (c / 8 < *p - && (p[1 + (c/8)] & (1 << (c % 8)))) - { - /* Are we starting a range? */ - if (last + 1 == c && ! in_range) - { - putchar ('-'); - in_range = 1; - } - /* Have we broken a range? */ - else if (last + 1 != c && in_range) - { - printchar (last); - in_range = 0; - } - - if (! in_range) - printchar (c); - - last = c; - } - - if (in_range) - printchar (last); - - putchar (']'); - - p += 1 + *p; - } - break; - - case begline: - printf ("/begline"); - break; - - case endline: - printf ("/endline"); - break; - - case on_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_jump to %d", p + mcnt - start); - break; - - case on_failure_keep_string_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/on_failure_keep_string_jump to %d", p + mcnt - start); - break; - - case dummy_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/dummy_failure_jump to %d", p + mcnt - start); - break; - - case push_dummy_failure: - printf ("/push_dummy_failure"); - break; - - case maybe_pop_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/maybe_pop_jump to %d", p + mcnt - start); - break; - - case pop_failure_jump: - extract_number_and_incr (&mcnt, &p); - printf ("/pop_failure_jump to %d", p + mcnt - start); - break; - - case jump_past_alt: - extract_number_and_incr (&mcnt, &p); - printf ("/jump_past_alt to %d", p + mcnt - start); - break; - - case jump: - extract_number_and_incr (&mcnt, &p); - printf ("/jump to %d", p + mcnt - start); - break; - - case succeed_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2); - break; - - case jump_n: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2); - break; - - case set_number_at: - extract_number_and_incr (&mcnt, &p); - extract_number_and_incr (&mcnt2, &p); - printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2); - break; - - case wordbound: - printf ("/wordbound"); - break; - - case notwordbound: - printf ("/notwordbound"); - break; - - case wordbeg: - printf ("/wordbeg"); - break; - - case wordend: - printf ("/wordend"); - -#ifdef emacs - case before_dot: - printf ("/before_dot"); - break; - - case at_dot: - printf ("/at_dot"); - break; - - case after_dot: - printf ("/after_dot"); - break; - - case syntaxspec: - printf ("/syntaxspec"); - mcnt = *p++; - printf ("/%d", mcnt); - break; - - case notsyntaxspec: - printf ("/notsyntaxspec"); - mcnt = *p++; - printf ("/%d", mcnt); - break; -#endif /* emacs */ - - case wordchar: - printf ("/wordchar"); - break; - - case notwordchar: - printf ("/notwordchar"); - break; - - case begbuf: - printf ("/begbuf"); - break; - - case endbuf: - printf ("/endbuf"); - break; - - default: - printf ("?%d", *(p-1)); - } - - putchar ('\n'); - } - - printf ("%d:\tend of pattern.\n", p - start); -} - - -void -print_compiled_pattern (bufp) - struct re_pattern_buffer *bufp; -{ - unsigned char *buffer = bufp->buffer; - - print_partial_compiled_pattern (buffer, buffer + bufp->used); - printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated); - - if (bufp->fastmap_accurate && bufp->fastmap) - { - printf ("fastmap: "); - print_fastmap (bufp->fastmap); - } - - printf ("re_nsub: %d\t", bufp->re_nsub); - printf ("regs_alloc: %d\t", bufp->regs_allocated); - printf ("can_be_null: %d\t", bufp->can_be_null); - printf ("newline_anchor: %d\n", bufp->newline_anchor); - printf ("no_sub: %d\t", bufp->no_sub); - printf ("not_bol: %d\t", bufp->not_bol); - printf ("not_eol: %d\t", bufp->not_eol); - printf ("syntax: %d\n", bufp->syntax); - /* Perhaps we should print the translate table? */ -} - - -void -print_double_string (where, string1, size1, string2, size2) - const char *where; - const char *string1; - const char *string2; - int size1; - int size2; -{ - unsigned this_char; - - if (where == NULL) - printf ("(null)"); - else - { - if (FIRST_STRING_P (where)) - { - for (this_char = where - string1; this_char < size1; this_char++) - printchar (string1[this_char]); - - where = string2; - } - - for (this_char = where - string2; this_char < size2; this_char++) - printchar (string2[this_char]); - } -} - -#else /* not DEBUG */ - -#undef assert -#define assert(e) - -#define DEBUG_STATEMENT(e) -#define DEBUG_PRINT1(x) -#define DEBUG_PRINT2(x1, x2) -#define DEBUG_PRINT3(x1, x2, x3) -#define DEBUG_PRINT4(x1, x2, x3, x4) -#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) -#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) - -#endif /* not DEBUG */ - -/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can - also be assigned to arbitrarily: each pattern buffer stores its own - syntax, so it can be changed between regex compilations. */ -reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS; - - -/* Specify the precise syntax of regexps for compilation. This provides - for compatibility for various utilities which historically have - different, incompatible syntaxes. - - The argument SYNTAX is a bit mask comprised of the various bits - defined in regex.h. We return the old syntax. */ - -reg_syntax_t -re_set_syntax (syntax) - reg_syntax_t syntax; -{ - reg_syntax_t ret = re_syntax_options; - - re_syntax_options = syntax; - return ret; -} - -/* This table gives an error message for each of the error codes listed - in regex.h. Obviously the order here has to be same as there. */ - -static const char *re_error_msg[] = - { NULL, /* REG_NOERROR */ - "No match", /* REG_NOMATCH */ - "Invalid regular expression", /* REG_BADPAT */ - "Invalid collation character", /* REG_ECOLLATE */ - "Invalid character class name", /* REG_ECTYPE */ - "Trailing backslash", /* REG_EESCAPE */ - "Invalid back reference", /* REG_ESUBREG */ - "Unmatched [ or [^", /* REG_EBRACK */ - "Unmatched ( or \\(", /* REG_EPAREN */ - "Unmatched \\{", /* REG_EBRACE */ - "Invalid content of \\{\\}", /* REG_BADBR */ - "Invalid range end", /* REG_ERANGE */ - "Memory exhausted", /* REG_ESPACE */ - "Invalid preceding regular expression", /* REG_BADRPT */ - "Premature end of regular expression", /* REG_EEND */ - "Regular expression too big", /* REG_ESIZE */ - "Unmatched ) or \\)", /* REG_ERPAREN */ - }; - -/* Avoiding alloca during matching, to placate r_alloc. */ - -/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the - searching and matching functions should not call alloca. On some - systems, alloca is implemented in terms of malloc, and if we're - using the relocating allocator routines, then malloc could cause a - relocation, which might (if the strings being searched are in the - ralloc heap) shift the data out from underneath the regexp - routines. - - Here's another reason to avoid allocation: Emacs - processes input from X in a signal handler; processing X input may - call malloc; if input arrives while a matching routine is calling - malloc, then we're scrod. But Emacs can't just block input while - calling matching routines; then we don't notice interrupts when - they come in. So, Emacs blocks input around all regexp calls - except the matching calls, which it leaves unprotected, in the - faith that they will not malloc. */ - -/* Normally, this is fine. */ -#define MATCH_MAY_ALLOCATE - -/* The match routines may not allocate if (1) they would do it with malloc - and (2) it's not safe for htem to use malloc. */ -#if (defined (C_ALLOCA) || defined (REGEX_MALLOC)) && (defined (emacs) || defined (REL_ALLOC)) -#undef MATCH_MAY_ALLOCATE -#endif - - -/* Failure stack declarations and macros; both re_compile_fastmap and - re_match_2 use a failure stack. These have to be macros because of - REGEX_ALLOCATE. */ - - -/* Number of failure points for which to initially allocate space - when matching. If this number is exceeded, we allocate more - space, so it is not a hard limit. */ -#ifndef INIT_FAILURE_ALLOC -#define INIT_FAILURE_ALLOC 5 -#endif - -/* Roughly the maximum number of failure points on the stack. Would be - exactly that if always used MAX_FAILURE_SPACE each time we failed. - This is a variable only so users of regex can assign to it; we never - change it ourselves. */ -int re_max_failures = 2000; - -typedef unsigned char *fail_stack_elt_t; - -typedef struct -{ - fail_stack_elt_t *stack; - unsigned size; - unsigned avail; /* Offset of next open position. */ -} fail_stack_type; - -#define FAIL_STACK_EMPTY() (fail_stack.avail == 0) -#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) -#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) -#define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) - - -/* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ - -#ifdef MATCH_MAY_ALLOCATE -#define INIT_FAIL_STACK() \ - do { \ - fail_stack.stack = (fail_stack_elt_t *) \ - REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ - \ - if (fail_stack.stack == NULL) \ - return -2; \ - \ - fail_stack.size = INIT_FAILURE_ALLOC; \ - fail_stack.avail = 0; \ - } while (0) -#else -#define INIT_FAIL_STACK() \ - do { \ - fail_stack.avail = 0; \ - } while (0) -#endif - - -/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. - - Return 1 if succeeds, and 0 if either ran out of memory - allocating space for it or it was already too large. - - REGEX_REALLOCATE requires `destination' be declared. */ - -#define DOUBLE_FAIL_STACK(fail_stack) \ - ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \ - ? 0 \ - : ((fail_stack).stack = (fail_stack_elt_t *) \ - REGEX_REALLOCATE ((fail_stack).stack, \ - (fail_stack).size * sizeof (fail_stack_elt_t), \ - ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \ - \ - (fail_stack).stack == NULL \ - ? 0 \ - : ((fail_stack).size <<= 1, \ - 1))) - - -/* Push PATTERN_OP on FAIL_STACK. - - Return 1 if was able to do so and 0 if ran out of memory allocating - space to do so. */ -#define PUSH_PATTERN_OP(pattern_op, fail_stack) \ - ((FAIL_STACK_FULL () \ - && !DOUBLE_FAIL_STACK (fail_stack)) \ - ? 0 \ - : ((fail_stack).stack[(fail_stack).avail++] = pattern_op, \ - 1)) - -/* This pushes an item onto the failure stack. Must be a four-byte - value. Assumes the variable `fail_stack'. Probably should only - be called from within `PUSH_FAILURE_POINT'. */ -#define PUSH_FAILURE_ITEM(item) \ - fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) (long) item - -/* The complement operation. Assumes `fail_stack' is nonempty. */ -#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] - -/* Used to omit pushing failure point id's when we're not debugging. */ -#ifdef DEBUG -#define DEBUG_PUSH PUSH_FAILURE_ITEM -#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM () -#else -#define DEBUG_PUSH(item) -#define DEBUG_POP(item_addr) -#endif - - -/* Push the information about the state we will need - if we ever fail back to it. - - Requires variables fail_stack, regstart, regend, reg_info, and - num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be - declared. - - Does `return FAILURE_CODE' if runs out of memory. */ - -#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ - do { \ - char *destination; \ - /* Must be int, so when we don't save any registers, the arithmetic \ - of 0 + -1 isn't done as unsigned. */ \ - int this_reg; \ - \ - DEBUG_STATEMENT (failure_id++); \ - DEBUG_STATEMENT (nfailure_points_pushed++); \ - DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ - DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ - DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ - \ - DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \ - DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ - \ - /* Ensure we have enough space allocated for what we will push. */ \ - while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ - { \ - if (!DOUBLE_FAIL_STACK (fail_stack)) \ - return failure_code; \ - \ - DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ - (fail_stack).size); \ - DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ - } \ - \ - /* Push the info, starting with the registers. */ \ - DEBUG_PRINT1 ("\n"); \ - \ - for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ - this_reg++) \ - { \ - DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \ - DEBUG_STATEMENT (num_regs_pushed++); \ - \ - DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ - PUSH_FAILURE_ITEM (regstart[this_reg]); \ - \ - DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ - PUSH_FAILURE_ITEM (regend[this_reg]); \ - \ - DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \ - DEBUG_PRINT2 (" match_null=%d", \ - REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ - DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ - DEBUG_PRINT2 (" matched_something=%d", \ - MATCHED_SOMETHING (reg_info[this_reg])); \ - DEBUG_PRINT2 (" ever_matched=%d", \ - EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ - DEBUG_PRINT1 ("\n"); \ - PUSH_FAILURE_ITEM (reg_info[this_reg].word); \ - } \ - \ - DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\ - PUSH_FAILURE_ITEM (lowest_active_reg); \ - \ - DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\ - PUSH_FAILURE_ITEM (highest_active_reg); \ - \ - DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \ - DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ - PUSH_FAILURE_ITEM (pattern_place); \ - \ - DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \ - DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ - size2); \ - DEBUG_PRINT1 ("'\n"); \ - PUSH_FAILURE_ITEM (string_place); \ - \ - DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ - DEBUG_PUSH (failure_id); \ - } while (0) - -/* This is the number of items that are pushed and popped on the stack - for each register. */ -#define NUM_REG_ITEMS 3 - -/* Individual items aside from the registers. */ -#ifdef DEBUG -#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ -#else -#define NUM_NONREG_ITEMS 4 -#endif - -/* We push at most this many items on the stack. */ -#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS) - -/* We actually push this many items. */ -#define NUM_FAILURE_ITEMS \ - ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \ - + NUM_NONREG_ITEMS) - -/* How many items can still be added to the stack without overflowing it. */ -#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) - - -/* Pops what PUSH_FAIL_STACK pushes. - - We restore into the parameters, all of which should be lvalues: - STR -- the saved data position. - PAT -- the saved pattern position. - LOW_REG, HIGH_REG -- the highest and lowest active registers. - REGSTART, REGEND -- arrays of string positions. - REG_INFO -- array of information about each subexpression. - - Also assumes the variables `fail_stack' and (if debugging), `bufp', - `pend', `string1', `size1', `string2', and `size2'. */ - -#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ -{ \ - DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ - int this_reg; \ - const unsigned char *string_temp; \ - \ - assert (!FAIL_STACK_EMPTY ()); \ - \ - /* Remove failure points and point to how many regs pushed. */ \ - DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ - DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ - DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ - \ - assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ - \ - DEBUG_POP (&failure_id); \ - DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ - \ - /* If the saved string location is NULL, it came from an \ - on_failure_keep_string_jump opcode, and we want to throw away the \ - saved NULL, thus retaining our current position in the string. */ \ - string_temp = POP_FAILURE_ITEM (); \ - if (string_temp != NULL) \ - str = (const char *) string_temp; \ - \ - DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ - DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ - DEBUG_PRINT1 ("'\n"); \ - \ - pat = (unsigned char *) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ - DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ - \ - /* Restore register info. */ \ - high_reg = (unsigned long) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ - \ - low_reg = (unsigned long) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ - \ - for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ - { \ - DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ - \ - reg_info[this_reg].word = POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ - \ - regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ - \ - regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ - DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ - } \ - \ - DEBUG_STATEMENT (nfailure_points_popped++); \ -} /* POP_FAILURE_POINT */ - - - -/* Structure for per-register (a.k.a. per-group) information. - This must not be longer than one word, because we push this value - onto the failure stack. Other register information, such as the - starting and ending positions (which are addresses), and the list of - inner groups (which is a bits list) are maintained in separate - variables. - - We are making a (strictly speaking) nonportable assumption here: that - the compiler will pack our bit fields into something that fits into - the type of `word', i.e., is something that fits into one item on the - failure stack. */ -typedef union -{ - fail_stack_elt_t word; - struct - { - /* This field is one if this group can match the empty string, - zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ -#define MATCH_NULL_UNSET_VALUE 3 - unsigned match_null_string_p : 2; - unsigned is_active : 1; - unsigned matched_something : 1; - unsigned ever_matched_something : 1; - } bits; -} register_info_type; - -#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) -#define IS_ACTIVE(R) ((R).bits.is_active) -#define MATCHED_SOMETHING(R) ((R).bits.matched_something) -#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) - - -/* Call this when have matched a real character; it sets `matched' flags - for the subexpressions which we are currently inside. Also records - that those subexprs have matched. */ -#define SET_REGS_MATCHED() \ - do \ - { \ - unsigned r; \ - for (r = lowest_active_reg; r <= highest_active_reg; r++) \ - { \ - MATCHED_SOMETHING (reg_info[r]) \ - = EVER_MATCHED_SOMETHING (reg_info[r]) \ - = 1; \ - } \ - } \ - while (0) - - -/* Registers are set to a sentinel when they haven't yet matched. */ -#define REG_UNSET_VALUE ((char *) -1) -#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) - - - -/* How do we implement a missing MATCH_MAY_ALLOCATE? - We make the fail stack a global thing, and then grow it to - re_max_failures when we compile. */ -#ifndef MATCH_MAY_ALLOCATE -static fail_stack_type fail_stack; - -static const char ** regstart, ** regend; -static const char ** old_regstart, ** old_regend; -static const char **best_regstart, **best_regend; -static register_info_type *reg_info; -static const char **reg_dummy; -static register_info_type *reg_info_dummy; -#endif - - -/* Subroutine declarations and macros for regex_compile. */ - -static void store_op1 (), store_op2 (); -static void insert_op1 (), insert_op2 (); -static boolean at_begline_loc_p (), at_endline_loc_p (); -static boolean group_in_compile_stack (); -static reg_errcode_t compile_range (); - -/* Fetch the next character in the uncompiled pattern---translating it - if necessary. Also cast from a signed character in the constant - string passed to us by the user to an unsigned char that we can use - as an array index (in, e.g., `translate'). */ -#define PATFETCH(c) \ - do {if (p == pend) return REG_EEND; \ - c = (unsigned char) *p++; \ - if (translate) c = translate[c]; \ - } while (0) - -/* Fetch the next character in the uncompiled pattern, with no - translation. */ -#define PATFETCH_RAW(c) \ - do {if (p == pend) return REG_EEND; \ - c = (unsigned char) *p++; \ - } while (0) - -/* Go backwards one character in the pattern. */ -#define PATUNFETCH p-- - - -/* If `translate' is non-null, return translate[D], else just D. We - cast the subscript to translate because some data is declared as - `char *', to avoid warnings when a string constant is passed. But - when we use a character as a subscript we must make it unsigned. */ -#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d)) - - -/* Macros for outputting the compiled pattern into `buffer'. */ - -/* If the buffer isn't allocated when it comes in, use this. */ -#define INIT_BUF_SIZE 32 - -/* Make sure we have at least N more bytes of space in buffer. */ -#define GET_BUFFER_SPACE(n) \ - while (b - bufp->buffer + (n) > bufp->allocated) \ - EXTEND_BUFFER () - -/* Make sure we have one more byte of buffer space and then add C to it. */ -#define BUF_PUSH(c) \ - do { \ - GET_BUFFER_SPACE (1); \ - *b++ = (unsigned char) (c); \ - } while (0) - - -/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ -#define BUF_PUSH_2(c1, c2) \ - do { \ - GET_BUFFER_SPACE (2); \ - *b++ = (unsigned char) (c1); \ - *b++ = (unsigned char) (c2); \ - } while (0) - - -/* As with BUF_PUSH_2, except for three bytes. */ -#define BUF_PUSH_3(c1, c2, c3) \ - do { \ - GET_BUFFER_SPACE (3); \ - *b++ = (unsigned char) (c1); \ - *b++ = (unsigned char) (c2); \ - *b++ = (unsigned char) (c3); \ - } while (0) - - -/* Store a jump with opcode OP at LOC to location TO. We store a - relative address offset by the three bytes the jump itself occupies. */ -#define STORE_JUMP(op, loc, to) \ - store_op1 (op, loc, (to) - (loc) - 3) - -/* Likewise, for a two-argument jump. */ -#define STORE_JUMP2(op, loc, to, arg) \ - store_op2 (op, loc, (to) - (loc) - 3, arg) - -/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ -#define INSERT_JUMP(op, loc, to) \ - insert_op1 (op, loc, (to) - (loc) - 3, b) - -/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ -#define INSERT_JUMP2(op, loc, to, arg) \ - insert_op2 (op, loc, (to) - (loc) - 3, arg, b) - - -/* This is not an arbitrary limit: the arguments which represent offsets - into the pattern are two bytes long. So if 2^16 bytes turns out to - be too small, many things would have to change. */ -#define MAX_BUF_SIZE (1L << 16) - - -/* Extend the buffer by twice its current size via realloc and - reset the pointers that pointed into the old block to point to the - correct places in the new one. If extending the buffer results in it - being larger than MAX_BUF_SIZE, then flag memory exhausted. */ -#define EXTEND_BUFFER() \ - do { \ - unsigned char *old_buffer = bufp->buffer; \ - if (bufp->allocated == MAX_BUF_SIZE) \ - return REG_ESIZE; \ - bufp->allocated <<= 1; \ - if (bufp->allocated > MAX_BUF_SIZE) \ - bufp->allocated = MAX_BUF_SIZE; \ - bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\ - if (bufp->buffer == NULL) \ - return REG_ESPACE; \ - /* If the buffer moved, move all the pointers into it. */ \ - if (old_buffer != bufp->buffer) \ - { \ - b = (b - old_buffer) + bufp->buffer; \ - begalt = (begalt - old_buffer) + bufp->buffer; \ - if (fixup_alt_jump) \ - fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\ - if (laststart) \ - laststart = (laststart - old_buffer) + bufp->buffer; \ - if (pending_exact) \ - pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ - } \ - } while (0) - - -/* Since we have one byte reserved for the register number argument to - {start,stop}_memory, the maximum number of groups we can report - things about is what fits in that byte. */ -#define MAX_REGNUM 255 - -/* But patterns can have more than `MAX_REGNUM' registers. We just - ignore the excess. */ -typedef unsigned regnum_t; - - -/* Macros for the compile stack. */ - -/* Since offsets can go either forwards or backwards, this type needs to - be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ -typedef int pattern_offset_t; - -typedef struct -{ - pattern_offset_t begalt_offset; - pattern_offset_t fixup_alt_jump; - pattern_offset_t inner_group_offset; - pattern_offset_t laststart_offset; - regnum_t regnum; -} compile_stack_elt_t; - - -typedef struct -{ - compile_stack_elt_t *stack; - unsigned size; - unsigned avail; /* Offset of next open position. */ -} compile_stack_type; - - -#define INIT_COMPILE_STACK_SIZE 32 - -#define COMPILE_STACK_EMPTY (compile_stack.avail == 0) -#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) - -/* The next available element. */ -#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) - - -/* Set the bit for character C in a list. */ -#define SET_LIST_BIT(c) \ - (b[((unsigned char) (c)) / BYTEWIDTH] \ - |= 1 << (((unsigned char) c) % BYTEWIDTH)) - - -/* Get the next unsigned number in the uncompiled pattern. */ -#define GET_UNSIGNED_NUMBER(num) \ - { if (p != pend) \ - { \ - PATFETCH (c); \ - while (ISDIGIT (c)) \ - { \ - if (num < 0) \ - num = 0; \ - num = num * 10 + c - '0'; \ - if (p == pend) \ - break; \ - PATFETCH (c); \ - } \ - } \ - } - -#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ - -#define IS_CHAR_CLASS(string) \ - (STREQ (string, "alpha") || STREQ (string, "upper") \ - || STREQ (string, "lower") || STREQ (string, "digit") \ - || STREQ (string, "alnum") || STREQ (string, "xdigit") \ - || STREQ (string, "space") || STREQ (string, "print") \ - || STREQ (string, "punct") || STREQ (string, "graph") \ - || STREQ (string, "cntrl") || STREQ (string, "blank")) - -/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. - Returns one of error codes defined in `regex.h', or zero for success. - - Assumes the `allocated' (and perhaps `buffer') and `translate' - fields are set in BUFP on entry. - - If it succeeds, results are put in BUFP (if it returns an error, the - contents of BUFP are undefined): - `buffer' is the compiled pattern; - `syntax' is set to SYNTAX; - `used' is set to the length of the compiled pattern; - `fastmap_accurate' is zero; - `re_nsub' is the number of subexpressions in PATTERN; - `not_bol' and `not_eol' are zero; - - The `fastmap' and `newline_anchor' fields are neither - examined nor set. */ - -/* Return, freeing storage we allocated. */ -#define FREE_STACK_RETURN(value) \ - return (free (compile_stack.stack), value) - -static reg_errcode_t -regex_compile (pattern, size, syntax, bufp) - const char *pattern; - int size; - reg_syntax_t syntax; - struct re_pattern_buffer *bufp; -{ - /* We fetch characters from PATTERN here. Even though PATTERN is - `char *' (i.e., signed), we declare these variables as unsigned, so - they can be reliably used as array indices. */ - register unsigned char c, c1; - - /* A random temporary spot in PATTERN. */ - const char *p1; - - /* Points to the end of the buffer, where we should append. */ - register unsigned char *b; - - /* Keeps track of unclosed groups. */ - compile_stack_type compile_stack; - - /* Points to the current (ending) position in the pattern. */ - const char *p = pattern; - const char *pend = pattern + size; - - /* How to translate the characters in the pattern. */ - char *translate = bufp->translate; - - /* Address of the count-byte of the most recently inserted `exactn' - command. This makes it possible to tell if a new exact-match - character can be added to that command or if the character requires - a new `exactn' command. */ - unsigned char *pending_exact = 0; - - /* Address of start of the most recently finished expression. - This tells, e.g., postfix * where to find the start of its - operand. Reset at the beginning of groups and alternatives. */ - unsigned char *laststart = 0; - - /* Address of beginning of regexp, or inside of last group. */ - unsigned char *begalt; - - /* Place in the uncompiled pattern (i.e., the {) to - which to go back if the interval is invalid. */ - const char *beg_interval; - - /* Address of the place where a forward jump should go to the end of - the containing expression. Each alternative of an `or' -- except the - last -- ends with a forward jump of this sort. */ - unsigned char *fixup_alt_jump = 0; - - /* Counts open-groups as they are encountered. Remembered for the - matching close-group on the compile stack, so the same register - number is put in the stop_memory as the start_memory. */ - regnum_t regnum = 0; - -#ifdef DEBUG - DEBUG_PRINT1 ("\nCompiling pattern: "); - if (debug) - { - unsigned debug_count; - - for (debug_count = 0; debug_count < size; debug_count++) - printchar (pattern[debug_count]); - putchar ('\n'); - } -#endif /* DEBUG */ - - /* Initialize the compile stack. */ - compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); - if (compile_stack.stack == NULL) - return REG_ESPACE; - - compile_stack.size = INIT_COMPILE_STACK_SIZE; - compile_stack.avail = 0; - - /* Initialize the pattern buffer. */ - bufp->syntax = syntax; - bufp->fastmap_accurate = 0; - bufp->not_bol = bufp->not_eol = 0; - - /* Set `used' to zero, so that if we return an error, the pattern - printer (for debugging) will think there's no pattern. We reset it - at the end. */ - bufp->used = 0; - - /* Always count groups, whether or not bufp->no_sub is set. */ - bufp->re_nsub = 0; - -#if !defined (emacs) && !defined (SYNTAX_TABLE) - /* Initialize the syntax table. */ - init_syntax_once (); -#endif - - if (bufp->allocated == 0) - { - if (bufp->buffer) - { /* If zero allocated, but buffer is non-null, try to realloc - enough space. This loses if buffer's address is bogus, but - that is the user's responsibility. */ - RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char); - } - else - { /* Caller did not allocate a buffer. Do it for them. */ - bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char); - } - if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE); - - bufp->allocated = INIT_BUF_SIZE; - } - - begalt = b = bufp->buffer; - - /* Loop through the uncompiled pattern until we're at the end. */ - while (p != pend) - { - PATFETCH (c); - - switch (c) - { - case '^': - { - if ( /* If at start of pattern, it's an operator. */ - p == pattern + 1 - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's come before. */ - || at_begline_loc_p (pattern, p, syntax)) - BUF_PUSH (begline); - else - goto normal_char; - } - break; - - - case '$': - { - if ( /* If at end of pattern, it's an operator. */ - p == pend - /* If context independent, it's an operator. */ - || syntax & RE_CONTEXT_INDEP_ANCHORS - /* Otherwise, depends on what's next. */ - || at_endline_loc_p (p, pend, syntax)) - BUF_PUSH (endline); - else - goto normal_char; - } - break; - - - case '+': - case '?': - if ((syntax & RE_BK_PLUS_QM) - || (syntax & RE_LIMITED_OPS)) - goto normal_char; - handle_plus: - case '*': - /* If there is no previous pattern... */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - FREE_STACK_RETURN (REG_BADRPT); - else if (!(syntax & RE_CONTEXT_INDEP_OPS)) - goto normal_char; - } - - { - /* Are we optimizing this jump? */ - boolean keep_string_p = false; - - /* 1 means zero (many) matches is allowed. */ - char zero_times_ok = 0, many_times_ok = 0; - - /* If there is a sequence of repetition chars, collapse it - down to just one (the right one). We can't combine - interval operators with these because of, e.g., `a{2}*', - which should only match an even number of `a's. */ - - for (;;) - { - zero_times_ok |= c != '+'; - many_times_ok |= c != '?'; - - if (p == pend) - break; - - PATFETCH (c); - - if (c == '*' - || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) - ; - - else if (syntax & RE_BK_PLUS_QM && c == '\\') - { - if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); - - PATFETCH (c1); - if (!(c1 == '+' || c1 == '?')) - { - PATUNFETCH; - PATUNFETCH; - break; - } - - c = c1; - } - else - { - PATUNFETCH; - break; - } - - /* If we get here, we found another repeat character. */ - } - - /* Star, etc. applied to an empty pattern is equivalent - to an empty pattern. */ - if (!laststart) - break; - - /* Now we know whether or not zero matches is allowed - and also whether or not two or more matches is allowed. */ - if (many_times_ok) - { /* More than one repetition is allowed, so put in at the - end a backward relative jump from `b' to before the next - jump we're going to put in below (which jumps from - laststart to after this jump). - - But if we are at the `*' in the exact sequence `.*\n', - insert an unconditional jump backwards to the ., - instead of the beginning of the loop. This way we only - push a failure point once, instead of every time - through the loop. */ - assert (p - 1 > pattern); - - /* Allocate the space for the jump. */ - GET_BUFFER_SPACE (3); - - /* We know we are not at the first character of the pattern, - because laststart was nonzero. And we've already - incremented `p', by the way, to be the character after - the `*'. Do we have to do something analogous here - for null bytes, because of RE_DOT_NOT_NULL? */ - if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') - && zero_times_ok - && p < pend && TRANSLATE (*p) == TRANSLATE ('\n') - && !(syntax & RE_DOT_NEWLINE)) - { /* We have .*\n. */ - STORE_JUMP (jump, b, laststart); - keep_string_p = true; - } - else - /* Anything else. */ - STORE_JUMP (maybe_pop_jump, b, laststart - 3); - - /* We've added more stuff to the buffer. */ - b += 3; - } - - /* On failure, jump from laststart to b + 3, which will be the - end of the buffer after this jump is inserted. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump - : on_failure_jump, - laststart, b + 3); - pending_exact = 0; - b += 3; - - if (!zero_times_ok) - { - /* At least one repetition is required, so insert a - `dummy_failure_jump' before the initial - `on_failure_jump' instruction of the loop. This - effects a skip over that instruction the first time - we hit that loop. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6); - b += 3; - } - } - break; - - - case '.': - laststart = b; - BUF_PUSH (anychar); - break; - - - case '[': - { - boolean had_char_class = false; - - if (p == pend) FREE_STACK_RETURN (REG_EBRACK); - - /* Ensure that we have enough space to push a charset: the - opcode, the length count, and the bitset; 34 bytes in all. */ - GET_BUFFER_SPACE (34); - - laststart = b; - - /* We test `*p == '^' twice, instead of using an if - statement, so we only need one BUF_PUSH. */ - BUF_PUSH (*p == '^' ? charset_not : charset); - if (*p == '^') - p++; - - /* Remember the first position in the bracket expression. */ - p1 = p; - - /* Push the number of bytes in the bitmap. */ - BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); - - /* Clear the whole map. */ - bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); - - /* charset_not matches newline according to a syntax bit. */ - if ((re_opcode_t) b[-2] == charset_not - && (syntax & RE_HAT_LISTS_NOT_NEWLINE)) - SET_LIST_BIT ('\n'); - - /* Read in characters and ranges, setting map bits. */ - for (;;) - { - if (p == pend) FREE_STACK_RETURN (REG_EBRACK); - - PATFETCH (c); - - /* \ might escape characters inside [...] and [^...]. */ - if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') - { - if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); - - PATFETCH (c1); - SET_LIST_BIT (c1); - continue; - } - - /* Could be the end of the bracket expression. If it's - not (i.e., when the bracket expression is `[]' so - far), the ']' character bit gets set way below. */ - if (c == ']' && p != p1 + 1) - break; - - /* Look ahead to see if it's a range when the last thing - was a character class. */ - if (had_char_class && c == '-' && *p != ']') - FREE_STACK_RETURN (REG_ERANGE); - - /* Look ahead to see if it's a range when the last thing - was a character: if this is a hyphen not at the - beginning or the end of a list, then it's the range - operator. */ - if (c == '-' - && !(p - 2 >= pattern && p[-2] == '[') - && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') - && *p != ']') - { - reg_errcode_t ret - = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); - } - - else if (p[0] == '-' && p[1] != ']') - { /* This handles ranges made up of characters only. */ - reg_errcode_t ret; - - /* Move past the `-'. */ - PATFETCH (c1); - - ret = compile_range (&p, pend, translate, syntax, b); - if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); - } - - /* See if we're at the beginning of a possible character - class. */ - - else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') - { /* Leave room for the null. */ - char str[CHAR_CLASS_MAX_LENGTH + 1]; - - PATFETCH (c); - c1 = 0; - - /* If pattern is `[[:'. */ - if (p == pend) FREE_STACK_RETURN (REG_EBRACK); - - for (;;) - { - PATFETCH (c); - if (c == ':' || c == ']' || p == pend - || c1 == CHAR_CLASS_MAX_LENGTH) - break; - str[c1++] = c; - } - str[c1] = '\0'; - - /* If isn't a word bracketed by `[:' and:`]': - undo the ending character, the letters, and leave - the leading `:' and `[' (but set bits for them). */ - if (c == ':' && *p == ']') - { - int ch; - boolean is_alnum = STREQ (str, "alnum"); - boolean is_alpha = STREQ (str, "alpha"); - boolean is_blank = STREQ (str, "blank"); - boolean is_cntrl = STREQ (str, "cntrl"); - boolean is_digit = STREQ (str, "digit"); - boolean is_graph = STREQ (str, "graph"); - boolean is_lower = STREQ (str, "lower"); - boolean is_print = STREQ (str, "print"); - boolean is_punct = STREQ (str, "punct"); - boolean is_space = STREQ (str, "space"); - boolean is_upper = STREQ (str, "upper"); - boolean is_xdigit = STREQ (str, "xdigit"); - - if (!IS_CHAR_CLASS (str)) - FREE_STACK_RETURN (REG_ECTYPE); - - /* Throw away the ] at the end of the character - class. */ - PATFETCH (c); - - if (p == pend) FREE_STACK_RETURN (REG_EBRACK); - - for (ch = 0; ch < 1 << BYTEWIDTH; ch++) - { - /* This was split into 3 if's to - avoid an arbitrary limit in some compiler. */ - if ( (is_alnum && ISALNUM (ch)) - || (is_alpha && ISALPHA (ch)) - || (is_blank && ISBLANK (ch)) - || (is_cntrl && ISCNTRL (ch))) - SET_LIST_BIT (ch); - if ( (is_digit && ISDIGIT (ch)) - || (is_graph && ISGRAPH (ch)) - || (is_lower && ISLOWER (ch)) - || (is_print && ISPRINT (ch))) - SET_LIST_BIT (ch); - if ( (is_punct && ISPUNCT (ch)) - || (is_space && ISSPACE (ch)) - || (is_upper && ISUPPER (ch)) - || (is_xdigit && ISXDIGIT (ch))) - SET_LIST_BIT (ch); - } - had_char_class = true; - } - else - { - c1++; - while (c1--) - PATUNFETCH; - SET_LIST_BIT ('['); - SET_LIST_BIT (':'); - had_char_class = false; - } - } - else - { - had_char_class = false; - SET_LIST_BIT (c); - } - } - - /* Discard any (non)matching list bytes that are all 0 at the - end of the map. Decrease the map-length byte too. */ - while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) - b[-1]--; - b += b[-1]; - } - break; - - - case '(': - if (syntax & RE_NO_BK_PARENS) - goto handle_open; - else - goto normal_char; - - - case ')': - if (syntax & RE_NO_BK_PARENS) - goto handle_close; - else - goto normal_char; - - - case '\n': - if (syntax & RE_NEWLINE_ALT) - goto handle_alt; - else - goto normal_char; - - - case '|': - if (syntax & RE_NO_BK_VBAR) - goto handle_alt; - else - goto normal_char; - - - case '{': - if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) - goto handle_interval; - else - goto normal_char; - - - case '\\': - if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); - - /* Do not translate the character after the \, so that we can - distinguish, e.g., \B from \b, even if we normally would - translate, e.g., B to b. */ - PATFETCH_RAW (c); - - switch (c) - { - case '(': - if (syntax & RE_NO_BK_PARENS) - goto normal_backslash; - - handle_open: - bufp->re_nsub++; - regnum++; - - if (COMPILE_STACK_FULL) - { - RETALLOC (compile_stack.stack, compile_stack.size << 1, - compile_stack_elt_t); - if (compile_stack.stack == NULL) return REG_ESPACE; - - compile_stack.size <<= 1; - } - - /* These are the values to restore when we hit end of this - group. They are all relative offsets, so that if the - whole pattern moves because of realloc, they will still - be valid. */ - COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer; - COMPILE_STACK_TOP.fixup_alt_jump - = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; - COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer; - COMPILE_STACK_TOP.regnum = regnum; - - /* We will eventually replace the 0 with the number of - groups inner to this one. But do not push a - start_memory for groups beyond the last one we can - represent in the compiled pattern. */ - if (regnum <= MAX_REGNUM) - { - COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2; - BUF_PUSH_3 (start_memory, regnum, 0); - } - - compile_stack.avail++; - - fixup_alt_jump = 0; - laststart = 0; - begalt = b; - /* If we've reached MAX_REGNUM groups, then this open - won't actually generate any code, so we'll have to - clear pending_exact explicitly. */ - pending_exact = 0; - break; - - - case ')': - if (syntax & RE_NO_BK_PARENS) goto normal_backslash; - - if (COMPILE_STACK_EMPTY) - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_backslash; - else - FREE_STACK_RETURN (REG_ERPAREN); - - handle_close: - if (fixup_alt_jump) - { /* Push a dummy failure point at the end of the - alternative for a possible future - `pop_failure_jump' to pop. See comments at - `push_dummy_failure' in `re_match_2'. */ - BUF_PUSH (push_dummy_failure); - - /* We allocated space for this jump when we assigned - to `fixup_alt_jump', in the `handle_alt' case below. */ - STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); - } - - /* See similar code for backslashed left paren above. */ - if (COMPILE_STACK_EMPTY) - if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) - goto normal_char; - else - FREE_STACK_RETURN (REG_ERPAREN); - - /* Since we just checked for an empty stack above, this - ``can't happen''. */ - assert (compile_stack.avail != 0); - { - /* We don't just want to restore into `regnum', because - later groups should continue to be numbered higher, - as in `(ab)c(de)' -- the second group is #2. */ - regnum_t this_group_regnum; - - compile_stack.avail--; - begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset; - fixup_alt_jump - = COMPILE_STACK_TOP.fixup_alt_jump - ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 - : 0; - laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset; - this_group_regnum = COMPILE_STACK_TOP.regnum; - /* If we've reached MAX_REGNUM groups, then this open - won't actually generate any code, so we'll have to - clear pending_exact explicitly. */ - pending_exact = 0; - - /* We're at the end of the group, so now we know how many - groups were inside this one. */ - if (this_group_regnum <= MAX_REGNUM) - { - unsigned char *inner_group_loc - = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset; - - *inner_group_loc = regnum - this_group_regnum; - BUF_PUSH_3 (stop_memory, this_group_regnum, - regnum - this_group_regnum); - } - } - break; - - - case '|': /* `\|'. */ - if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) - goto normal_backslash; - handle_alt: - if (syntax & RE_LIMITED_OPS) - goto normal_char; - - /* Insert before the previous alternative a jump which - jumps to this alternative if the former fails. */ - GET_BUFFER_SPACE (3); - INSERT_JUMP (on_failure_jump, begalt, b + 6); - pending_exact = 0; - b += 3; - - /* The alternative before this one has a jump after it - which gets executed if it gets matched. Adjust that - jump so it will jump to this alternative's analogous - jump (put in below, which in turn will jump to the next - (if any) alternative's such jump, etc.). The last such - jump jumps to the correct final destination. A picture: - _____ _____ - | | | | - | v | v - a | b | c - - If we are at `b', then fixup_alt_jump right now points to a - three-byte space after `a'. We'll put in the jump, set - fixup_alt_jump to right after `b', and leave behind three - bytes which we'll fill in when we get to after `c'. */ - - if (fixup_alt_jump) - STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - - /* Mark and leave space for a jump after this alternative, - to be filled in later either by next alternative or - when know we're at the end of a series of alternatives. */ - fixup_alt_jump = b; - GET_BUFFER_SPACE (3); - b += 3; - - laststart = 0; - begalt = b; - break; - - - case '{': - /* If \{ is a literal. */ - if (!(syntax & RE_INTERVALS) - /* If we're at `\{' and it's not the open-interval - operator. */ - || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) - || (p - 2 == pattern && p == pend)) - goto normal_backslash; - - handle_interval: - { - /* If got here, then the syntax allows intervals. */ - - /* At least (most) this many matches must be made. */ - int lower_bound = -1, upper_bound = -1; - - beg_interval = p - 1; - - if (p == pend) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - FREE_STACK_RETURN (REG_EBRACE); - } - - GET_UNSIGNED_NUMBER (lower_bound); - - if (c == ',') - { - GET_UNSIGNED_NUMBER (upper_bound); - if (upper_bound < 0) upper_bound = RE_DUP_MAX; - } - else - /* Interval such as `{1}' => match exactly once. */ - upper_bound = lower_bound; - - if (lower_bound < 0 || upper_bound > RE_DUP_MAX - || lower_bound > upper_bound) - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - FREE_STACK_RETURN (REG_BADBR); - } - - if (!(syntax & RE_NO_BK_BRACES)) - { - if (c != '\\') FREE_STACK_RETURN (REG_EBRACE); - - PATFETCH (c); - } - - if (c != '}') - { - if (syntax & RE_NO_BK_BRACES) - goto unfetch_interval; - else - FREE_STACK_RETURN (REG_BADBR); - } - - /* We just parsed a valid interval. */ - - /* If it's invalid to have no preceding re. */ - if (!laststart) - { - if (syntax & RE_CONTEXT_INVALID_OPS) - FREE_STACK_RETURN (REG_BADRPT); - else if (syntax & RE_CONTEXT_INDEP_OPS) - laststart = b; - else - goto unfetch_interval; - } - - /* If the upper bound is zero, don't want to succeed at - all; jump from `laststart' to `b + 3', which will be - the end of the buffer after we insert the jump. */ - if (upper_bound == 0) - { - GET_BUFFER_SPACE (3); - INSERT_JUMP (jump, laststart, b + 3); - b += 3; - } - - /* Otherwise, we have a nontrivial interval. When - we're all done, the pattern will look like: - set_number_at - set_number_at - succeed_n - - jump_n - (The upper bound and `jump_n' are omitted if - `upper_bound' is 1, though.) */ - else - { /* If the upper bound is > 1, we need to insert - more at the end of the loop. */ - unsigned nbytes = 10 + (upper_bound > 1) * 10; - - GET_BUFFER_SPACE (nbytes); - - /* Initialize lower bound of the `succeed_n', even - though it will be set during matching by its - attendant `set_number_at' (inserted next), - because `re_compile_fastmap' needs to know. - Jump to the `jump_n' we might insert below. */ - INSERT_JUMP2 (succeed_n, laststart, - b + 5 + (upper_bound > 1) * 5, - lower_bound); - b += 5; - - /* Code to initialize the lower bound. Insert - before the `succeed_n'. The `5' is the last two - bytes of this `set_number_at', plus 3 bytes of - the following `succeed_n'. */ - insert_op2 (set_number_at, laststart, 5, lower_bound, b); - b += 5; - - if (upper_bound > 1) - { /* More than one repetition is allowed, so - append a backward jump to the `succeed_n' - that starts this interval. - - When we've reached this during matching, - we'll have matched the interval once, so - jump back only `upper_bound - 1' times. */ - STORE_JUMP2 (jump_n, b, laststart + 5, - upper_bound - 1); - b += 5; - - /* The location we want to set is the second - parameter of the `jump_n'; that is `b-2' as - an absolute address. `laststart' will be - the `set_number_at' we're about to insert; - `laststart+3' the number to set, the source - for the relative address. But we are - inserting into the middle of the pattern -- - so everything is getting moved up by 5. - Conclusion: (b - 2) - (laststart + 3) + 5, - i.e., b - laststart. - - We insert this at the beginning of the loop - so that if we fail during matching, we'll - reinitialize the bounds. */ - insert_op2 (set_number_at, laststart, b - laststart, - upper_bound - 1, b); - b += 5; - } - } - pending_exact = 0; - beg_interval = NULL; - } - break; - - unfetch_interval: - /* If an invalid interval, match the characters as literals. */ - assert (beg_interval); - p = beg_interval; - beg_interval = NULL; - - /* normal_char and normal_backslash need `c'. */ - PATFETCH (c); - - if (!(syntax & RE_NO_BK_BRACES)) - { - if (p > pattern && p[-1] == '\\') - goto normal_backslash; - } - goto normal_char; - -#ifdef emacs - /* There is no way to specify the before_dot and after_dot - operators. rms says this is ok. --karl */ - case '=': - BUF_PUSH (at_dot); - break; - - case 's': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); - break; - - case 'S': - laststart = b; - PATFETCH (c); - BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); - break; -#endif /* emacs */ - - - case 'w': - laststart = b; - BUF_PUSH (wordchar); - break; - - - case 'W': - laststart = b; - BUF_PUSH (notwordchar); - break; - - - case '<': - BUF_PUSH (wordbeg); - break; - - case '>': - BUF_PUSH (wordend); - break; - - case 'b': - BUF_PUSH (wordbound); - break; - - case 'B': - BUF_PUSH (notwordbound); - break; - - case '`': - BUF_PUSH (begbuf); - break; - - case '\'': - BUF_PUSH (endbuf); - break; - - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - if (syntax & RE_NO_BK_REFS) - goto normal_char; - - c1 = c - '0'; - - if (c1 > regnum) - FREE_STACK_RETURN (REG_ESUBREG); - - /* Can't back reference to a subexpression if inside of it. */ - if (group_in_compile_stack (compile_stack, c1)) - goto normal_char; - - laststart = b; - BUF_PUSH_2 (duplicate, c1); - break; - - - case '+': - case '?': - if (syntax & RE_BK_PLUS_QM) - goto handle_plus; - else - goto normal_backslash; - - default: - normal_backslash: - /* You might think it would be useful for \ to mean - not to translate; but if we don't translate it - it will never match anything. */ - c = TRANSLATE (c); - goto normal_char; - } - break; - - - default: - /* Expects the character in `c'. */ - normal_char: - /* If no exactn currently being built. */ - if (!pending_exact - - /* If last exactn not at current position. */ - || pending_exact + *pending_exact + 1 != b - - /* We have only one byte following the exactn for the count. */ - || *pending_exact == (1 << BYTEWIDTH) - 1 - - /* If followed by a repetition operator. */ - || *p == '*' || *p == '^' - || ((syntax & RE_BK_PLUS_QM) - ? *p == '\\' && (p[1] == '+' || p[1] == '?') - : (*p == '+' || *p == '?')) - || ((syntax & RE_INTERVALS) - && ((syntax & RE_NO_BK_BRACES) - ? *p == '{' - : (p[0] == '\\' && p[1] == '{')))) - { - /* Start building a new exactn. */ - - laststart = b; - - BUF_PUSH_2 (exactn, 0); - pending_exact = b - 1; - } - - BUF_PUSH (c); - (*pending_exact)++; - break; - } /* switch (c) */ - } /* while p != pend */ - - - /* Through the pattern now. */ - - if (fixup_alt_jump) - STORE_JUMP (jump_past_alt, fixup_alt_jump, b); - - if (!COMPILE_STACK_EMPTY) - FREE_STACK_RETURN (REG_EPAREN); - - free (compile_stack.stack); - - /* We have succeeded; set the length of the buffer. */ - bufp->used = b - bufp->buffer; - -#ifdef DEBUG - if (debug) - { - DEBUG_PRINT1 ("\nCompiled pattern: \n"); - print_compiled_pattern (bufp); - } -#endif /* DEBUG */ - -#ifndef MATCH_MAY_ALLOCATE - /* Initialize the failure stack to the largest possible stack. This - isn't necessary unless we're trying to avoid calling alloca in - the search and match routines. */ - { - int num_regs = bufp->re_nsub + 1; - - /* Since DOUBLE_FAIL_STACK refuses to double only if the current size - is strictly greater than re_max_failures, the largest possible stack - is 2 * re_max_failures failure points. */ - if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) - { - fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); - -#ifdef emacs - if (! fail_stack.stack) - fail_stack.stack - = (fail_stack_elt_t *) xmalloc (fail_stack.size - * sizeof (fail_stack_elt_t)); - else - fail_stack.stack - = (fail_stack_elt_t *) xrealloc (fail_stack.stack, - (fail_stack.size - * sizeof (fail_stack_elt_t))); -#else /* not emacs */ - if (! fail_stack.stack) - fail_stack.stack - = (fail_stack_elt_t *) malloc (fail_stack.size - * sizeof (fail_stack_elt_t)); - else - fail_stack.stack - = (fail_stack_elt_t *) realloc (fail_stack.stack, - (fail_stack.size - * sizeof (fail_stack_elt_t))); -#endif /* not emacs */ - } - - /* Initialize some other variables the matcher uses. */ - RETALLOC_IF (regstart, num_regs, const char *); - RETALLOC_IF (regend, num_regs, const char *); - RETALLOC_IF (old_regstart, num_regs, const char *); - RETALLOC_IF (old_regend, num_regs, const char *); - RETALLOC_IF (best_regstart, num_regs, const char *); - RETALLOC_IF (best_regend, num_regs, const char *); - RETALLOC_IF (reg_info, num_regs, register_info_type); - RETALLOC_IF (reg_dummy, num_regs, const char *); - RETALLOC_IF (reg_info_dummy, num_regs, register_info_type); - } -#endif - - return REG_NOERROR; -} /* regex_compile */ - -/* Subroutines for `regex_compile'. */ - -/* Store OP at LOC followed by two-byte integer parameter ARG. */ - -static void -store_op1 (op, loc, arg) - re_opcode_t op; - unsigned char *loc; - int arg; -{ - *loc = (unsigned char) op; - STORE_NUMBER (loc + 1, arg); -} - - -/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ - -static void -store_op2 (op, loc, arg1, arg2) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; -{ - *loc = (unsigned char) op; - STORE_NUMBER (loc + 1, arg1); - STORE_NUMBER (loc + 3, arg2); -} - - -/* Copy the bytes from LOC to END to open up three bytes of space at LOC - for OP followed by two-byte integer parameter ARG. */ - -static void -insert_op1 (op, loc, arg, end) - re_opcode_t op; - unsigned char *loc; - int arg; - unsigned char *end; -{ - register unsigned char *pfrom = end; - register unsigned char *pto = end + 3; - - while (pfrom != loc) - *--pto = *--pfrom; - - store_op1 (op, loc, arg); -} - - -/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ - -static void -insert_op2 (op, loc, arg1, arg2, end) - re_opcode_t op; - unsigned char *loc; - int arg1, arg2; - unsigned char *end; -{ - register unsigned char *pfrom = end; - register unsigned char *pto = end + 5; - - while (pfrom != loc) - *--pto = *--pfrom; - - store_op2 (op, loc, arg1, arg2); -} - - -/* P points to just after a ^ in PATTERN. Return true if that ^ comes - after an alternative or a begin-subexpression. We assume there is at - least one character before the ^. */ - -static boolean -at_begline_loc_p (pattern, p, syntax) - const char *pattern, *p; - reg_syntax_t syntax; -{ - const char *prev = p - 2; - boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; - - return - /* After a subexpression? */ - (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) - /* After an alternative? */ - || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); -} - - -/* The dual of at_begline_loc_p. This one is for $. We assume there is - at least one character after the $, i.e., `P < PEND'. */ - -static boolean -at_endline_loc_p (p, pend, syntax) - const char *p, *pend; - int syntax; -{ - const char *next = p; - boolean next_backslash = *next == '\\'; - const char *next_next = p + 1 < pend ? p + 1 : NULL; - - return - /* Before a subexpression? */ - (syntax & RE_NO_BK_PARENS ? *next == ')' - : next_backslash && next_next && *next_next == ')') - /* Before an alternative? */ - || (syntax & RE_NO_BK_VBAR ? *next == '|' - : next_backslash && next_next && *next_next == '|'); -} - - -/* Returns true if REGNUM is in one of COMPILE_STACK's elements and - false if it's not. */ - -static boolean -group_in_compile_stack (compile_stack, regnum) - compile_stack_type compile_stack; - regnum_t regnum; -{ - int this_element; - - for (this_element = compile_stack.avail - 1; - this_element >= 0; - this_element--) - if (compile_stack.stack[this_element].regnum == regnum) - return true; - - return false; -} - - -/* Read the ending character of a range (in a bracket expression) from the - uncompiled pattern *P_PTR (which ends at PEND). We assume the - starting character is in `P[-2]'. (`P[-1]' is the character `-'.) - Then we set the translation of all bits between the starting and - ending characters (inclusive) in the compiled pattern B. - - Return an error code. - - We use these short variable names so we can use the same macros as - `regex_compile' itself. */ - -static reg_errcode_t -compile_range (p_ptr, pend, translate, syntax, b) - const char **p_ptr, *pend; - char *translate; - reg_syntax_t syntax; - unsigned char *b; -{ - unsigned this_char; - - const char *p = *p_ptr; - int range_start, range_end; - - if (p == pend) - return REG_ERANGE; - - /* Even though the pattern is a signed `char *', we need to fetch - with unsigned char *'s; if the high bit of the pattern character - is set, the range endpoints will be negative if we fetch using a - signed char *. - - We also want to fetch the endpoints without translating them; the - appropriate translation is done in the bit-setting loop below. */ - /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *. */ - range_start = ((const unsigned char *) p)[-2]; - range_end = ((const unsigned char *) p)[0]; - - /* Have to increment the pointer into the pattern string, so the - caller isn't still at the ending character. */ - (*p_ptr)++; - - /* If the start is after the end, the range is empty. */ - if (range_start > range_end) - return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; - - /* Here we see why `this_char' has to be larger than an `unsigned - char' -- the range is inclusive, so if `range_end' == 0xff - (assuming 8-bit characters), we would otherwise go into an infinite - loop, since all characters <= 0xff. */ - for (this_char = range_start; this_char <= range_end; this_char++) - { - SET_LIST_BIT (TRANSLATE (this_char)); - } - - return REG_NOERROR; -} - -/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in - BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible - characters can start a string that matches the pattern. This fastmap - is used by re_search to skip quickly over impossible starting points. - - The caller must supply the address of a (1 << BYTEWIDTH)-byte data - area as BUFP->fastmap. - - We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in - the pattern buffer. - - Returns 0 if we succeed, -2 if an internal error. */ - -int -re_compile_fastmap (bufp) - struct re_pattern_buffer *bufp; -{ - int j, k; -#ifdef MATCH_MAY_ALLOCATE - fail_stack_type fail_stack; -#endif -#ifndef REGEX_MALLOC - char *destination; -#endif - /* We don't push any register information onto the failure stack. */ - unsigned num_regs = 0; - - register char *fastmap = bufp->fastmap; - unsigned char *pattern = bufp->buffer; - unsigned long size = bufp->used; - unsigned char *p = pattern; - register unsigned char *pend = pattern + size; - - /* Assume that each path through the pattern can be null until - proven otherwise. We set this false at the bottom of switch - statement, to which we get only if a particular path doesn't - match the empty string. */ - boolean path_can_be_null = true; - - /* We aren't doing a `succeed_n' to begin with. */ - boolean succeed_n_p = false; - - assert (fastmap != NULL && p != NULL); - - INIT_FAIL_STACK (); - bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ - bufp->fastmap_accurate = 1; /* It will be when we're done. */ - bufp->can_be_null = 0; - - while (p != pend || !FAIL_STACK_EMPTY ()) - { - if (p == pend) - { - bufp->can_be_null |= path_can_be_null; - - /* Reset for next path. */ - path_can_be_null = true; - - p = fail_stack.stack[--fail_stack.avail]; - } - - /* We should never be about to go beyond the end of the pattern. */ - assert (p < pend); - -#ifdef SWITCH_ENUM_BUG - switch ((int) ((re_opcode_t) *p++)) -#else - switch ((re_opcode_t) *p++) -#endif - { - - /* I guess the idea here is to simply not bother with a fastmap - if a backreference is used, since it's too hard to figure out - the fastmap for the corresponding group. Setting - `can_be_null' stops `re_search_2' from using the fastmap, so - that is all we do. */ - case duplicate: - bufp->can_be_null = 1; - return 0; - - - /* Following are the cases which match a character. These end - with `break'. */ - - case exactn: - fastmap[p[1]] = 1; - break; - - - case charset: - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) - if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) - fastmap[j] = 1; - break; - - - case charset_not: - /* Chars beyond end of map must be allowed. */ - for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; - - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) - if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) - fastmap[j] = 1; - break; - - - case wordchar: - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) == Sword) - fastmap[j] = 1; - break; - - - case notwordchar: - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) != Sword) - fastmap[j] = 1; - break; - - - case anychar: - { - int fastmap_newline = fastmap['\n']; - - /* `.' matches anything ... */ - for (j = 0; j < (1 << BYTEWIDTH); j++) - fastmap[j] = 1; - - /* ... except perhaps newline. */ - if (!(bufp->syntax & RE_DOT_NEWLINE)) - fastmap['\n'] = fastmap_newline; - - /* Return if we have already set `can_be_null'; if we have, - then the fastmap is irrelevant. Something's wrong here. */ - else if (bufp->can_be_null) - return 0; - - /* Otherwise, have to check alternative paths. */ - break; - } - -#ifdef emacs - case syntaxspec: - k = *p++; - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) == (enum syntaxcode) k) - fastmap[j] = 1; - break; - - - case notsyntaxspec: - k = *p++; - for (j = 0; j < (1 << BYTEWIDTH); j++) - if (SYNTAX (j) != (enum syntaxcode) k) - fastmap[j] = 1; - break; - - - /* All cases after this match the empty string. These end with - `continue'. */ - - - case before_dot: - case at_dot: - case after_dot: - continue; -#endif /* not emacs */ - - - case no_op: - case begline: - case endline: - case begbuf: - case endbuf: - case wordbound: - case notwordbound: - case wordbeg: - case wordend: - case push_dummy_failure: - continue; - - - case jump_n: - case pop_failure_jump: - case maybe_pop_jump: - case jump: - case jump_past_alt: - case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; - if (j > 0) - continue; - - /* Jump backward implies we just went through the body of a - loop and matched nothing. Opcode jumped to should be - `on_failure_jump' or `succeed_n'. Just treat it like an - ordinary jump. For a * loop, it has pushed its failure - point already; if so, discard that as redundant. */ - if ((re_opcode_t) *p != on_failure_jump - && (re_opcode_t) *p != succeed_n) - continue; - - p++; - EXTRACT_NUMBER_AND_INCR (j, p); - p += j; - - /* If what's on the stack is where we are now, pop it. */ - if (!FAIL_STACK_EMPTY () - && fail_stack.stack[fail_stack.avail - 1] == p) - fail_stack.avail--; - - continue; - - - case on_failure_jump: - case on_failure_keep_string_jump: - handle_on_failure_jump: - EXTRACT_NUMBER_AND_INCR (j, p); - - /* For some patterns, e.g., `(a?)?', `p+j' here points to the - end of the pattern. We don't want to push such a point, - since when we restore it above, entering the switch will - increment `p' past the end of the pattern. We don't need - to push such a point since we obviously won't find any more - fastmap entries beyond `pend'. Such a pattern can match - the null string, though. */ - if (p + j < pend) - { - if (!PUSH_PATTERN_OP (p + j, fail_stack)) - return -2; - } - else - bufp->can_be_null = 1; - - if (succeed_n_p) - { - EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ - succeed_n_p = false; - } - - continue; - - - case succeed_n: - /* Get to the number of times to succeed. */ - p += 2; - - /* Increment p past the n for when k != 0. */ - EXTRACT_NUMBER_AND_INCR (k, p); - if (k == 0) - { - p -= 4; - succeed_n_p = true; /* Spaghetti code alert. */ - goto handle_on_failure_jump; - } - continue; - - - case set_number_at: - p += 4; - continue; - - - case start_memory: - case stop_memory: - p += 2; - continue; - - - default: - abort (); /* We have listed all the cases. */ - } /* switch *p++ */ - - /* Getting here means we have found the possible starting - characters for one path of the pattern -- and that the empty - string does not match. We need not follow this path further. - Instead, look at the next alternative (remembered on the - stack), or quit if no more. The test at the top of the loop - does these things. */ - path_can_be_null = false; - p = pend; - } /* while p */ - - /* Set `can_be_null' for the last path (also the first path, if the - pattern is empty). */ - bufp->can_be_null |= path_can_be_null; - return 0; -} /* re_compile_fastmap */ - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use - this memory for recording register information. STARTS and ENDS - must be allocated using the malloc library routine, and must each - be at least NUM_REGS * sizeof (regoff_t) bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ - -void -re_set_registers (bufp, regs, num_regs, starts, ends) - struct re_pattern_buffer *bufp; - struct re_registers *regs; - unsigned num_regs; - regoff_t *starts, *ends; -{ - if (num_regs) - { - bufp->regs_allocated = REGS_REALLOCATE; - regs->num_regs = num_regs; - regs->start = starts; - regs->end = ends; - } - else - { - bufp->regs_allocated = REGS_UNALLOCATED; - regs->num_regs = 0; - regs->start = regs->end = (regoff_t *) 0; - } -} - -/* Searching routines. */ - -/* Like re_search_2, below, but only one string is specified, and - doesn't let you say where to stop matching. */ - -int -re_search (bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; -{ - return re_search_2 (bufp, NULL, 0, string, size, startpos, range, - regs, size); -} - - -/* Using the compiled pattern in BUFP->buffer, first tries to match the - virtual concatenation of STRING1 and STRING2, starting first at index - STARTPOS, then at STARTPOS + 1, and so on. - - STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. - - RANGE is how far to scan while trying to match. RANGE = 0 means try - only at STARTPOS; in general, the last start tried is STARTPOS + - RANGE. - - In REGS, return the indices of the virtual concatenation of STRING1 - and STRING2 that matched the entire BUFP->buffer and its contained - subexpressions. - - Do not consider matching one past the index STOP in the virtual - concatenation of STRING1 and STRING2. - - We return either the position in the strings at which the match was - found, -1 if no match, or -2 if error (such as failure - stack overflow). */ - -int -re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int startpos; - int range; - struct re_registers *regs; - int stop; -{ - int val; - register char *fastmap = bufp->fastmap; - register char *translate = bufp->translate; - int total_size = size1 + size2; - int endpos = startpos + range; - - /* Check for out-of-range STARTPOS. */ - if (startpos < 0 || startpos > total_size) - return -1; - - /* Fix up RANGE if it might eventually take us outside - the virtual concatenation of STRING1 and STRING2. */ - if (endpos < -1) - range = -1 - startpos; - else if (endpos > total_size) - range = total_size - startpos; - - /* If the search isn't to be a backwards one, don't waste time in a - search for a pattern that must be anchored. */ - if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) - { - if (startpos > 0) - return -1; - else - range = 1; - } - - /* Update the fastmap now if not correct already. */ - if (fastmap && !bufp->fastmap_accurate) - if (re_compile_fastmap (bufp) == -2) - return -2; - - /* Loop through the string, looking for a place to start matching. */ - for (;;) - { - /* If a fastmap is supplied, skip quickly over characters that - cannot be the start of a match. If the pattern can match the - null string, however, we don't need to skip characters; we want - the first null string. */ - if (fastmap && startpos < total_size && !bufp->can_be_null) - { - if (range > 0) /* Searching forwards. */ - { - register const char *d; - register int lim = 0; - int irange = range; - - if (startpos < size1 && startpos + range >= size1) - lim = range - (size1 - startpos); - - d = (startpos >= size1 ? string2 - size1 : string1) + startpos; - - /* Written out as an if-else to avoid testing `translate' - inside the loop. */ - if (translate) - while (range > lim - && !fastmap[(unsigned char) - translate[(unsigned char) *d++]]) - range--; - else - while (range > lim && !fastmap[(unsigned char) *d++]) - range--; - - startpos += irange - range; - } - else /* Searching backwards. */ - { - register char c = (size1 == 0 || startpos >= size1 - ? string2[startpos - size1] - : string1[startpos]); - - if (!fastmap[(unsigned char) TRANSLATE (c)]) - goto advance; - } - } - - /* If can't match the null string, and that's all we have left, fail. */ - if (range >= 0 && startpos == total_size && fastmap - && !bufp->can_be_null) - return -1; - - val = re_match_2_internal (bufp, string1, size1, string2, size2, - startpos, regs, stop); -#ifndef REGEX_MALLOC -#ifdef C_ALLOCA - alloca (0); -#endif -#endif - - if (val >= 0) - return startpos; - - if (val == -2) - return -2; - - advance: - if (!range) - break; - else if (range > 0) - { - range--; - startpos++; - } - else - { - range++; - startpos--; - } - } - return -1; -} /* re_search_2 */ - -/* Declarations and macros for re_match_2. */ - -static int bcmp_translate (); -static boolean alt_match_null_string_p (), - common_op_match_null_string_p (), - group_match_null_string_p (); - -/* This converts PTR, a pointer into one of the search strings `string1' - and `string2' into an offset from the beginning of that string. */ -#define POINTER_TO_OFFSET(ptr) \ - (FIRST_STRING_P (ptr) \ - ? ((regoff_t) ((ptr) - string1)) \ - : ((regoff_t) ((ptr) - string2 + size1))) - -/* Macros for dealing with the split strings in re_match_2. */ - -#define MATCHING_IN_FIRST_STRING (dend == end_match_1) - -/* Call before fetching a character with *d. This switches over to - string2 if necessary. */ -#define PREFETCH() \ - while (d == dend) \ - { \ - /* End of string2 => fail. */ \ - if (dend == end_match_2) \ - goto fail; \ - /* End of string1 => advance to string2. */ \ - d = string2; \ - dend = end_match_2; \ - } - - -/* Test if at very beginning or at very end of the virtual concatenation - of `string1' and `string2'. If only one string, it's `string2'. */ -#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) -#define AT_STRINGS_END(d) ((d) == end2) - - -/* Test if D points to a character which is word-constituent. We have - two special cases to check for: if past the end of string1, look at - the first character in string2; and if before the beginning of - string2, look at the last character in string1. */ -#define WORDCHAR_P(d) \ - (SYNTAX ((d) == end1 ? *string2 \ - : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ - == Sword) - -/* Test if the character before D and the one at D differ with respect - to being word-constituent. */ -#define AT_WORD_BOUNDARY(d) \ - (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ - || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) - - -/* Free everything we malloc. */ -#ifdef MATCH_MAY_ALLOCATE -#ifdef REGEX_MALLOC -#define FREE_VAR(var) if (var) free (var); var = NULL -#define FREE_VARIABLES() \ - do { \ - FREE_VAR (fail_stack.stack); \ - FREE_VAR (regstart); \ - FREE_VAR (regend); \ - FREE_VAR (old_regstart); \ - FREE_VAR (old_regend); \ - FREE_VAR (best_regstart); \ - FREE_VAR (best_regend); \ - FREE_VAR (reg_info); \ - FREE_VAR (reg_dummy); \ - FREE_VAR (reg_info_dummy); \ - } while (0) -#else /* not REGEX_MALLOC */ -/* This used to do alloca (0), but now we do that in the caller. */ -#define FREE_VARIABLES() /* Nothing */ -#endif /* not REGEX_MALLOC */ -#else -#define FREE_VARIABLES() /* Do nothing! */ -#endif /* not MATCH_MAY_ALLOCATE */ - -/* These values must meet several constraints. They must not be valid - register values; since we have a limit of 255 registers (because - we use only one byte in the pattern for the register number), we can - use numbers larger than 255. They must differ by 1, because of - NUM_FAILURE_ITEMS above. And the value for the lowest register must - be larger than the value for the highest register, so we do not try - to actually save any registers when none are active. */ -#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) -#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) - -/* Matching routines. */ - -#ifndef emacs /* Emacs never uses this. */ -/* re_match is like re_match_2 except it takes only a single string. */ - -int -re_match (bufp, string, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, pos; - struct re_registers *regs; -{ - int result = re_match_2_internal (bufp, NULL, 0, string, size, - pos, regs, size); - alloca (0); - return result; -} -#endif /* not emacs */ - - -/* re_match_2 matches the compiled pattern in BUFP against the - the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 - and SIZE2, respectively). We start matching at POS, and stop - matching at STOP. - - If REGS is non-null and the `no_sub' field of BUFP is nonzero, we - store offsets for the substring each group matched in REGS. See the - documentation for exactly how many groups we fill. - - We return -1 if no match, -2 if an internal error (such as the - failure stack overflowing). Otherwise, we return the length of the - matched substring. */ - -int -re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; -{ - int result = re_match_2_internal (bufp, string1, size1, string2, size2, - pos, regs, stop); - alloca (0); - return result; -} - -/* This is a separate function so that we can force an alloca cleanup - afterwards. */ -static int -re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop) - struct re_pattern_buffer *bufp; - const char *string1, *string2; - int size1, size2; - int pos; - struct re_registers *regs; - int stop; -{ - /* General temporaries. */ - int mcnt; - unsigned char *p1; - - /* Just past the end of the corresponding string. */ - const char *end1, *end2; - - /* Pointers into string1 and string2, just past the last characters in - each to consider matching. */ - const char *end_match_1, *end_match_2; - - /* Where we are in the data, and the end of the current string. */ - const char *d, *dend; - - /* Where we are in the pattern, and the end of the pattern. */ - unsigned char *p = bufp->buffer; - register unsigned char *pend = p + bufp->used; - - /* Mark the opcode just after a start_memory, so we can test for an - empty subpattern when we get to the stop_memory. */ - unsigned char *just_past_start_mem = 0; - - /* We use this to map every character in the string. */ - char *translate = bufp->translate; - - /* Failure point stack. Each place that can handle a failure further - down the line pushes a failure point on this stack. It consists of - restart, regend, and reg_info for all registers corresponding to - the subexpressions we're currently inside, plus the number of such - registers, and, finally, two char *'s. The first char * is where - to resume scanning the pattern; the second one is where to resume - scanning the strings. If the latter is zero, the failure point is - a ``dummy''; if a failure happens and the failure point is a dummy, - it gets discarded and the next next one is tried. */ -#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ - fail_stack_type fail_stack; -#endif -#ifdef DEBUG - static unsigned failure_id = 0; - unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; -#endif - - /* We fill all the registers internally, independent of what we - return, for use in backreferences. The number here includes - an element for register zero. */ - unsigned num_regs = bufp->re_nsub + 1; - - /* The currently active registers. */ - unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG; - unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG; - - /* Information on the contents of registers. These are pointers into - the input strings; they record just what was matched (on this - attempt) by a subexpression part of the pattern, that is, the - regnum-th regstart pointer points to where in the pattern we began - matching and the regnum-th regend points to right after where we - stopped matching the regnum-th subexpression. (The zeroth register - keeps track of what the whole pattern matches.) */ -#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ - const char **regstart, **regend; -#endif - - /* If a group that's operated upon by a repetition operator fails to - match anything, then the register for its start will need to be - restored because it will have been set to wherever in the string we - are when we last see its open-group operator. Similarly for a - register's end. */ -#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ - const char **old_regstart, **old_regend; -#endif - - /* The is_active field of reg_info helps us keep track of which (possibly - nested) subexpressions we are currently in. The matched_something - field of reg_info[reg_num] helps us tell whether or not we have - matched any of the pattern so far this time through the reg_num-th - subexpression. These two fields get reset each time through any - loop their register is in. */ -#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ - register_info_type *reg_info; -#endif - - /* The following record the register info as found in the above - variables when we find a match better than any we've seen before. - This happens as we backtrack through the failure points, which in - turn happens only if we have not yet matched the entire string. */ - unsigned best_regs_set = false; -#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ - const char **best_regstart, **best_regend; -#endif - - /* Logically, this is `best_regend[0]'. But we don't want to have to - allocate space for that if we're not allocating space for anything - else (see below). Also, we never need info about register 0 for - any of the other register vectors, and it seems rather a kludge to - treat `best_regend' differently than the rest. So we keep track of - the end of the best match so far in a separate variable. We - initialize this to NULL so that when we backtrack the first time - and need to test it, it's not garbage. */ - const char *match_end = NULL; - - /* Used when we pop values we don't care about. */ -#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ - const char **reg_dummy; - register_info_type *reg_info_dummy; -#endif - -#ifdef DEBUG - /* Counts the total number of registers pushed. */ - unsigned num_regs_pushed = 0; -#endif - - DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); - - INIT_FAIL_STACK (); - -#ifdef MATCH_MAY_ALLOCATE - /* Do not bother to initialize all the register variables if there are - no groups in the pattern, as it takes a fair amount of time. If - there are groups, we include space for register 0 (the whole - pattern), even though we never use it, since it simplifies the - array indexing. We should fix this. */ - if (bufp->re_nsub) - { - regstart = REGEX_TALLOC (num_regs, const char *); - regend = REGEX_TALLOC (num_regs, const char *); - old_regstart = REGEX_TALLOC (num_regs, const char *); - old_regend = REGEX_TALLOC (num_regs, const char *); - best_regstart = REGEX_TALLOC (num_regs, const char *); - best_regend = REGEX_TALLOC (num_regs, const char *); - reg_info = REGEX_TALLOC (num_regs, register_info_type); - reg_dummy = REGEX_TALLOC (num_regs, const char *); - reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type); - - if (!(regstart && regend && old_regstart && old_regend && reg_info - && best_regstart && best_regend && reg_dummy && reg_info_dummy)) - { - FREE_VARIABLES (); - return -2; - } - } -#if defined (REGEX_MALLOC) - else - { - /* We must initialize all our variables to NULL, so that - `FREE_VARIABLES' doesn't try to free them. */ - regstart = regend = old_regstart = old_regend = best_regstart - = best_regend = reg_dummy = NULL; - reg_info = reg_info_dummy = (register_info_type *) NULL; - } -#endif /* REGEX_MALLOC */ -#endif /* MATCH_MAY_ALLOCATE */ - - /* The starting position is bogus. */ - if (pos < 0 || pos > size1 + size2) - { - FREE_VARIABLES (); - return -1; - } - - /* Initialize subexpression text positions to -1 to mark ones that no - start_memory/stop_memory has been seen for. Also initialize the - register information struct. */ - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - regstart[mcnt] = regend[mcnt] - = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; - - REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; - IS_ACTIVE (reg_info[mcnt]) = 0; - MATCHED_SOMETHING (reg_info[mcnt]) = 0; - EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; - } - - /* We move `string1' into `string2' if the latter's empty -- but not if - `string1' is null. */ - if (size2 == 0 && string1 != NULL) - { - string2 = string1; - size2 = size1; - string1 = 0; - size1 = 0; - } - end1 = string1 + size1; - end2 = string2 + size2; - - /* Compute where to stop matching, within the two strings. */ - if (stop <= size1) - { - end_match_1 = string1 + stop; - end_match_2 = string2; - } - else - { - end_match_1 = end1; - end_match_2 = string2 + stop - size1; - } - - /* `p' scans through the pattern as `d' scans through the data. - `dend' is the end of the input string that `d' points within. `d' - is advanced into the following input string whenever necessary, but - this happens before fetching; therefore, at the beginning of the - loop, `d' can be pointing at the end of a string, but it cannot - equal `string2'. */ - if (size1 > 0 && pos <= size1) - { - d = string1 + pos; - dend = end_match_1; - } - else - { - d = string2 + pos - size1; - dend = end_match_2; - } - - DEBUG_PRINT1 ("The compiled pattern is: "); - DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); - DEBUG_PRINT1 ("The string to match is: `"); - DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); - DEBUG_PRINT1 ("'\n"); - - /* This loops over pattern commands. It exits by returning from the - function if the match is complete, or it drops through if the match - fails at this starting point in the input data. */ - for (;;) - { - DEBUG_PRINT2 ("\n0x%x: ", p); - - if (p == pend) - { /* End of pattern means we might have succeeded. */ - DEBUG_PRINT1 ("end of pattern ... "); - - /* If we haven't matched the entire string, and we want the - longest match, try backtracking. */ - if (d != end_match_2) - { - /* 1 if this match ends in the same string (string1 or string2) - as the best previous match. */ - boolean same_str_p = (FIRST_STRING_P (match_end) - == MATCHING_IN_FIRST_STRING); - /* 1 if this match is the best seen so far. */ - boolean best_match_p; - - /* AIX compiler got confused when this was combined - with the previous declaration. */ - if (same_str_p) - best_match_p = d > match_end; - else - best_match_p = !MATCHING_IN_FIRST_STRING; - - DEBUG_PRINT1 ("backtracking.\n"); - - if (!FAIL_STACK_EMPTY ()) - { /* More failure points to try. */ - - /* If exceeds best match so far, save it. */ - if (!best_regs_set || best_match_p) - { - best_regs_set = true; - match_end = d; - - DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); - - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - best_regstart[mcnt] = regstart[mcnt]; - best_regend[mcnt] = regend[mcnt]; - } - } - goto fail; - } - - /* If no failure points, don't restore garbage. And if - last match is real best match, don't restore second - best one. */ - else if (best_regs_set && !best_match_p) - { - restore_best_regs: - /* Restore best match. It may happen that `dend == - end_match_1' while the restored d is in string2. - For example, the pattern `x.*y.*z' against the - strings `x-' and `y-z-', if the two strings are - not consecutive in memory. */ - DEBUG_PRINT1 ("Restoring best registers.\n"); - - d = match_end; - dend = ((d >= string1 && d <= end1) - ? end_match_1 : end_match_2); - - for (mcnt = 1; mcnt < num_regs; mcnt++) - { - regstart[mcnt] = best_regstart[mcnt]; - regend[mcnt] = best_regend[mcnt]; - } - } - } /* d != end_match_2 */ - - DEBUG_PRINT1 ("Accepting match.\n"); - - /* If caller wants register contents data back, do it. */ - if (regs && !bufp->no_sub) - { - /* Have the register data arrays been allocated? */ - if (bufp->regs_allocated == REGS_UNALLOCATED) - { /* No. So allocate them with malloc. We need one - extra element beyond `num_regs' for the `-1' marker - GNU code uses. */ - regs->num_regs = MAX (RE_NREGS, num_regs + 1); - regs->start = TALLOC (regs->num_regs, regoff_t); - regs->end = TALLOC (regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - bufp->regs_allocated = REGS_REALLOCATE; - } - else if (bufp->regs_allocated == REGS_REALLOCATE) - { /* Yes. If we need more elements than were already - allocated, reallocate them. If we need fewer, just - leave it alone. */ - if (regs->num_regs < num_regs + 1) - { - regs->num_regs = num_regs + 1; - RETALLOC (regs->start, regs->num_regs, regoff_t); - RETALLOC (regs->end, regs->num_regs, regoff_t); - if (regs->start == NULL || regs->end == NULL) - return -2; - } - } - else - { - /* These braces fend off a "empty body in an else-statement" - warning under GCC when assert expands to nothing. */ - assert (bufp->regs_allocated == REGS_FIXED); - } - - /* Convert the pointer data in `regstart' and `regend' to - indices. Register zero has to be set differently, - since we haven't kept track of any info for it. */ - if (regs->num_regs > 0) - { - regs->start[0] = pos; - regs->end[0] = (MATCHING_IN_FIRST_STRING - ? ((regoff_t) (d - string1)) - : ((regoff_t) (d - string2 + size1))); - } - - /* Go through the first `min (num_regs, regs->num_regs)' - registers, since that is all we initialized. */ - for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++) - { - if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) - regs->start[mcnt] = regs->end[mcnt] = -1; - else - { - regs->start[mcnt] - = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); - regs->end[mcnt] - = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); - } - } - - /* If the regs structure we return has more elements than - were in the pattern, set the extra elements to -1. If - we (re)allocated the registers, this is the case, - because we always allocate enough to have at least one - -1 at the end. */ - for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++) - regs->start[mcnt] = regs->end[mcnt] = -1; - } /* regs && !bufp->no_sub */ - - FREE_VARIABLES (); - DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", - nfailure_points_pushed, nfailure_points_popped, - nfailure_points_pushed - nfailure_points_popped); - DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); - - mcnt = d - pos - (MATCHING_IN_FIRST_STRING - ? string1 - : string2 - size1); - - DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); - - return mcnt; - } - - /* Otherwise match next pattern command. */ -#ifdef SWITCH_ENUM_BUG - switch ((int) ((re_opcode_t) *p++)) -#else - switch ((re_opcode_t) *p++) -#endif - { - /* Ignore these. Used to ignore the n of succeed_n's which - currently have n == 0. */ - case no_op: - DEBUG_PRINT1 ("EXECUTING no_op.\n"); - break; - - - /* Match the next n pattern characters exactly. The following - byte in the pattern defines n, and the n bytes after that - are the characters to match. */ - case exactn: - mcnt = *p++; - DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); - - /* This is written out as an if-else so we don't waste time - testing `translate' inside the loop. */ - if (translate) - { - do - { - PREFETCH (); - if (translate[(unsigned char) *d++] != (char) *p++) - goto fail; - } - while (--mcnt); - } - else - { - do - { - PREFETCH (); - if (*d++ != (char) *p++) goto fail; - } - while (--mcnt); - } - SET_REGS_MATCHED (); - break; - - - /* Match any character except possibly a newline or a null. */ - case anychar: - DEBUG_PRINT1 ("EXECUTING anychar.\n"); - - PREFETCH (); - - if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') - || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) - goto fail; - - SET_REGS_MATCHED (); - DEBUG_PRINT2 (" Matched `%d'.\n", *d); - d++; - break; - - - case charset: - case charset_not: - { - register unsigned char c; - boolean not = (re_opcode_t) *(p - 1) == charset_not; - - DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : ""); - - PREFETCH (); - c = TRANSLATE (*d); /* The character to match. */ - - /* Cast to `unsigned' instead of `unsigned char' in case the - bit list is a full 32 bytes long. */ - if (c < (unsigned) (*p * BYTEWIDTH) - && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) - not = !not; - - p += 1 + *p; - - if (!not) goto fail; - - SET_REGS_MATCHED (); - d++; - break; - } - - - /* The beginning of a group is represented by start_memory. - The arguments are the register number in the next byte, and the - number of groups inner to this one in the next. The text - matched within the group is recorded (in the internal - registers data structure) under the register number. */ - case start_memory: - DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]); - - /* Find out if this group can match the empty string. */ - p1 = p; /* To send to group_match_null_string_p. */ - - if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[*p]) - = group_match_null_string_p (&p1, pend, reg_info); - - /* Save the position in the string where we were the last time - we were at this open-group operator in case the group is - operated upon by a repetition operator, e.g., with `(a*)*b' - against `ab'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regstart[*p]) ? d : regstart[*p] - : regstart[*p]; - DEBUG_PRINT2 (" old_regstart: %d\n", - POINTER_TO_OFFSET (old_regstart[*p])); - - regstart[*p] = d; - DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); - - IS_ACTIVE (reg_info[*p]) = 1; - MATCHED_SOMETHING (reg_info[*p]) = 0; - - /* This is the new highest active register. */ - highest_active_reg = *p; - - /* If nothing was active before, this is the new lowest active - register. */ - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *p; - - /* Move past the register number and inner group count. */ - p += 2; - just_past_start_mem = p; - break; - - - /* The stop_memory opcode represents the end of a group. Its - arguments are the same as start_memory's: the register - number, and the number of inner groups. */ - case stop_memory: - DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]); - - /* We need to save the string position the last time we were at - this close-group operator in case the group is operated - upon by a repetition operator, e.g., with `((a*)*(b*)*)*' - against `aba'; then we want to ignore where we are now in - the string in case this attempt to match fails. */ - old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) - ? REG_UNSET (regend[*p]) ? d : regend[*p] - : regend[*p]; - DEBUG_PRINT2 (" old_regend: %d\n", - POINTER_TO_OFFSET (old_regend[*p])); - - regend[*p] = d; - DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); - - /* This register isn't active anymore. */ - IS_ACTIVE (reg_info[*p]) = 0; - - /* If this was the only register active, nothing is active - anymore. */ - if (lowest_active_reg == highest_active_reg) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - { /* We must scan for the new highest active register, since - it isn't necessarily one less than now: consider - (a(b)c(d(e)f)g). When group 3 ends, after the f), the - new highest active register is 1. */ - unsigned char r = *p - 1; - while (r > 0 && !IS_ACTIVE (reg_info[r])) - r--; - - /* If we end up at register zero, that means that we saved - the registers as the result of an `on_failure_jump', not - a `start_memory', and we jumped to past the innermost - `stop_memory'. For example, in ((.)*) we save - registers 1 and 2 as a result of the *, but when we pop - back to the second ), we are at the stop_memory 1. - Thus, nothing is active. */ - if (r == 0) - { - lowest_active_reg = NO_LOWEST_ACTIVE_REG; - highest_active_reg = NO_HIGHEST_ACTIVE_REG; - } - else - highest_active_reg = r; - } - - /* If just failed to match something this time around with a - group that's operated on by a repetition operator, try to - force exit from the ``loop'', and restore the register - information for this group that we had before trying this - last match. */ - if ((!MATCHED_SOMETHING (reg_info[*p]) - || just_past_start_mem == p - 1) - && (p + 2) < pend) - { - boolean is_a_jump_n = false; - - p1 = p + 2; - mcnt = 0; - switch ((re_opcode_t) *p1++) - { - case jump_n: - is_a_jump_n = true; - case pop_failure_jump: - case maybe_pop_jump: - case jump: - case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if (is_a_jump_n) - p1 += 2; - break; - - default: - /* do nothing */ ; - } - p1 += mcnt; - - /* If the next operation is a jump backwards in the pattern - to an on_failure_jump right before the start_memory - corresponding to this stop_memory, exit from the loop - by forcing a failure after pushing on the stack the - on_failure_jump's jump in the pattern, and d. */ - if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump - && (re_opcode_t) p1[3] == start_memory && p1[4] == *p) - { - /* If this group ever matched anything, then restore - what its registers were before trying this last - failed match, e.g., with `(a*)*b' against `ab' for - regstart[1], and, e.g., with `((a*)*(b*)*)*' - against `aba' for regend[3]. - - Also restore the registers for inner groups for, - e.g., `((a*)(b*))*' against `aba' (register 3 would - otherwise get trashed). */ - - if (EVER_MATCHED_SOMETHING (reg_info[*p])) - { - unsigned r; - - EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; - - /* Restore this and inner groups' (if any) registers. */ - for (r = *p; r < *p + *(p + 1); r++) - { - regstart[r] = old_regstart[r]; - - /* xx why this test? */ - if ((long) old_regend[r] >= (long) regstart[r]) - regend[r] = old_regend[r]; - } - } - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - PUSH_FAILURE_POINT (p1 + mcnt, d, -2); - - goto fail; - } - } - - /* Move past the register number and the inner group count. */ - p += 2; - break; - - - /* \ has been turned into a `duplicate' command which is - followed by the numeric value of as the register number. */ - case duplicate: - { - register const char *d2, *dend2; - int regno = *p++; /* Get which register to match against. */ - DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); - - /* Can't back reference a group which we've never matched. */ - if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) - goto fail; - - /* Where in input to try to start matching. */ - d2 = regstart[regno]; - - /* Where to stop matching; if both the place to start and - the place to stop matching are in the same string, then - set to the place to stop, otherwise, for now have to use - the end of the first string. */ - - dend2 = ((FIRST_STRING_P (regstart[regno]) - == FIRST_STRING_P (regend[regno])) - ? regend[regno] : end_match_1); - for (;;) - { - /* If necessary, advance to next segment in register - contents. */ - while (d2 == dend2) - { - if (dend2 == end_match_2) break; - if (dend2 == regend[regno]) break; - - /* End of string1 => advance to string2. */ - d2 = string2; - dend2 = regend[regno]; - } - /* At end of register contents => success */ - if (d2 == dend2) break; - - /* If necessary, advance to next segment in data. */ - PREFETCH (); - - /* How many characters left in this segment to match. */ - mcnt = dend - d; - - /* Want how many consecutive characters we can match in - one shot, so, if necessary, adjust the count. */ - if (mcnt > dend2 - d2) - mcnt = dend2 - d2; - - /* Compare that many; failure if mismatch, else move - past them. */ - if (translate - ? bcmp_translate (d, d2, mcnt, translate) - : bcmp (d, d2, mcnt)) - goto fail; - d += mcnt, d2 += mcnt; - } - } - break; - - - /* begline matches the empty string at the beginning of the string - (unless `not_bol' is set in `bufp'), and, if - `newline_anchor' is set, after newlines. */ - case begline: - DEBUG_PRINT1 ("EXECUTING begline.\n"); - - if (AT_STRINGS_BEG (d)) - { - if (!bufp->not_bol) break; - } - else if (d[-1] == '\n' && bufp->newline_anchor) - { - break; - } - /* In all other cases, we fail. */ - goto fail; - - - /* endline is the dual of begline. */ - case endline: - DEBUG_PRINT1 ("EXECUTING endline.\n"); - - if (AT_STRINGS_END (d)) - { - if (!bufp->not_eol) break; - } - - /* We have to ``prefetch'' the next character. */ - else if ((d == end1 ? *string2 : *d) == '\n' - && bufp->newline_anchor) - { - break; - } - goto fail; - - - /* Match at the very beginning of the data. */ - case begbuf: - DEBUG_PRINT1 ("EXECUTING begbuf.\n"); - if (AT_STRINGS_BEG (d)) - break; - goto fail; - - - /* Match at the very end of the data. */ - case endbuf: - DEBUG_PRINT1 ("EXECUTING endbuf.\n"); - if (AT_STRINGS_END (d)) - break; - goto fail; - - - /* on_failure_keep_string_jump is used to optimize `.*\n'. It - pushes NULL as the value for the string on the stack. Then - `pop_failure_point' will keep the current value for the - string, instead of restoring it. To see why, consider - matching `foo\nbar' against `.*\n'. The .* matches the foo; - then the . fails against the \n. But the next thing we want - to do is match the \n against the \n; if we restored the - string value, we would be back at the foo. - - Because this is used only in specific cases, we don't need to - check all the things that `on_failure_jump' does, to make - sure the right things get saved on the stack. Hence we don't - share its code. The only reason to push anything on the - stack at all is that otherwise we would have to change - `anychar's code to do something besides goto fail in this - case; that seems worse than this. */ - case on_failure_keep_string_jump: - DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); - - PUSH_FAILURE_POINT (p + mcnt, NULL, -2); - break; - - - /* Uses of on_failure_jump: - - Each alternative starts with an on_failure_jump that points - to the beginning of the next alternative. Each alternative - except the last ends with a jump that in effect jumps past - the rest of the alternatives. (They really jump to the - ending jump of the following alternative, because tensioning - these jumps is a hassle.) - - Repeats start with an on_failure_jump that points past both - the repetition text and either the following jump or - pop_failure_jump back to this on_failure_jump. */ - case on_failure_jump: - on_failure: - DEBUG_PRINT1 ("EXECUTING on_failure_jump"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); - - /* If this on_failure_jump comes right before a group (i.e., - the original * applied to a group), save the information - for that group and all inner ones, so that if we fail back - to this point, the group's information will be correct. - For example, in \(a*\)*\1, we need the preceding group, - and in \(\(a*\)b*\)\2, we need the inner group. */ - - /* We can't use `p' to check ahead because we push - a failure point to `p + mcnt' after we do this. */ - p1 = p; - - /* We need to skip no_op's before we look for the - start_memory in case this on_failure_jump is happening as - the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 - against aba. */ - while (p1 < pend && (re_opcode_t) *p1 == no_op) - p1++; - - if (p1 < pend && (re_opcode_t) *p1 == start_memory) - { - /* We have a new highest active register now. This will - get reset at the start_memory we are about to get to, - but we will have saved all the registers relevant to - this repetition op, as described above. */ - highest_active_reg = *(p1 + 1) + *(p1 + 2); - if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) - lowest_active_reg = *(p1 + 1); - } - - DEBUG_PRINT1 (":\n"); - PUSH_FAILURE_POINT (p + mcnt, d, -2); - break; - - - /* A smart repeat ends with `maybe_pop_jump'. - We change it to either `pop_failure_jump' or `jump'. */ - case maybe_pop_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); - { - register unsigned char *p2 = p; - - /* Compare the beginning of the repeat with what in the - pattern follows its end. If we can establish that there - is nothing that they would both match, i.e., that we - would have to backtrack because of (as in, e.g., `a*a') - then we can change to pop_failure_jump, because we'll - never have to backtrack. - - This is not true in the case of alternatives: in - `(a|ab)*' we do need to backtrack to the `ab' alternative - (e.g., if the string was `ab'). But instead of trying to - detect that here, the alternative has put on a dummy - failure point which is what we will end up popping. */ - - /* Skip over open/close-group commands. - If what follows this loop is a ...+ construct, - look at what begins its body, since we will have to - match at least one of that. */ - while (1) - { - if (p2 + 2 < pend - && ((re_opcode_t) *p2 == stop_memory - || (re_opcode_t) *p2 == start_memory)) - p2 += 3; - else if (p2 + 6 < pend - && (re_opcode_t) *p2 == dummy_failure_jump) - p2 += 6; - else - break; - } - - p1 = p + mcnt; - /* p1[0] ... p1[2] are the `on_failure_jump' corresponding - to the `maybe_finalize_jump' of this case. Examine what - follows. */ - - /* If we're at the end of the pattern, we can change. */ - if (p2 == pend) - { - /* Consider what happens when matching ":\(.*\)" - against ":/". I don't really understand this code - yet. */ - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 - (" End of pattern: change to `pop_failure_jump'.\n"); - } - - else if ((re_opcode_t) *p2 == exactn - || (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) - { - register unsigned char c - = *p2 == (unsigned char) endline ? '\n' : p2[2]; - - if ((re_opcode_t) p1[3] == exactn && p1[5] != c) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", - c, p1[5]); - } - - else if ((re_opcode_t) p1[3] == charset - || (re_opcode_t) p1[3] == charset_not) - { - int not = (re_opcode_t) p1[3] == charset_not; - - if (c < (unsigned char) (p1[4] * BYTEWIDTH) - && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) - not = !not; - - /* `not' is equal to 1 if c would match, which means - that we can't change to pop_failure_jump. */ - if (!not) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); - } - } - } - else if ((re_opcode_t) *p2 == charset) - { -#ifdef DEBUG - register unsigned char c - = *p2 == (unsigned char) endline ? '\n' : p2[2]; -#endif - - if ((re_opcode_t) p1[3] == exactn - && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4] - && (p2[1 + p1[4] / BYTEWIDTH] - & (1 << (p1[4] % BYTEWIDTH))))) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", - c, p1[5]); - } - - else if ((re_opcode_t) p1[3] == charset_not) - { - int idx; - /* We win if the charset_not inside the loop - lists every character listed in the charset after. */ - for (idx = 0; idx < (int) p2[1]; idx++) - if (! (p2[2 + idx] == 0 - || (idx < (int) p1[4] - && ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) - break; - - if (idx == p2[1]) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); - } - } - else if ((re_opcode_t) p1[3] == charset) - { - int idx; - /* We win if the charset inside the loop - has no overlap with the one after the loop. */ - for (idx = 0; - idx < (int) p2[1] && idx < (int) p1[4]; - idx++) - if ((p2[2 + idx] & p1[5 + idx]) != 0) - break; - - if (idx == p2[1] || idx == p1[4]) - { - p[-3] = (unsigned char) pop_failure_jump; - DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); - } - } - } - } - p -= 2; /* Point at relative address again. */ - if ((re_opcode_t) p[-1] != pop_failure_jump) - { - p[-1] = (unsigned char) jump; - DEBUG_PRINT1 (" Match => jump.\n"); - goto unconditional_jump; - } - /* Note fall through. */ - - - /* The end of a simple repeat has a pop_failure_jump back to - its matching on_failure_jump, where the latter will push a - failure point. The pop_failure_jump takes off failure - points put on by this pop_failure_jump's matching - on_failure_jump; we got through the pattern to here from the - matching on_failure_jump, so didn't fail. */ - case pop_failure_jump: - { - /* We need to pass separate storage for the lowest and - highest registers, even though we don't care about the - actual values. Otherwise, we will restore only one - register from the stack, since lowest will == highest in - `pop_failure_point'. */ - unsigned dummy_low_reg, dummy_high_reg; - unsigned char *pdummy; - const char *sdummy; - - DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); - POP_FAILURE_POINT (sdummy, pdummy, - dummy_low_reg, dummy_high_reg, - reg_dummy, reg_dummy, reg_info_dummy); - } - /* Note fall through. */ - - - /* Unconditionally jump (without popping any failure points). */ - case jump: - unconditional_jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ - DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); - p += mcnt; /* Do the jump. */ - DEBUG_PRINT2 ("(to 0x%x).\n", p); - break; - - - /* We need this opcode so we can detect where alternatives end - in `group_match_null_string_p' et al. */ - case jump_past_alt: - DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); - goto unconditional_jump; - - - /* Normally, the on_failure_jump pushes a failure point, which - then gets popped at pop_failure_jump. We will end up at - pop_failure_jump, also, and with a pattern of, say, `a+', we - are skipping over the on_failure_jump, so we have to push - something meaningless for pop_failure_jump to pop. */ - case dummy_failure_jump: - DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); - /* It doesn't matter what we push for the string here. What - the code at `fail' tests is the value for the pattern. */ - PUSH_FAILURE_POINT (0, 0, -2); - goto unconditional_jump; - - - /* At the end of an alternative, we need to push a dummy failure - point in case we are followed by a `pop_failure_jump', because - we don't want the failure point for the alternative to be - popped. For example, matching `(a|ab)*' against `aab' - requires that we match the `ab' alternative. */ - case push_dummy_failure: - DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); - /* See comments just above at `dummy_failure_jump' about the - two zeroes. */ - PUSH_FAILURE_POINT (0, 0, -2); - break; - - /* Have to succeed matching what follows at least n times. - After that, handle like `on_failure_jump'. */ - case succeed_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); - - assert (mcnt >= 0); - /* Originally, this is how many times we HAVE to succeed. */ - if (mcnt > 0) - { - mcnt--; - p += 2; - STORE_NUMBER_AND_INCR (p, mcnt); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt); - } - else if (mcnt == 0) - { - DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2); - p[2] = (unsigned char) no_op; - p[3] = (unsigned char) no_op; - goto on_failure; - } - break; - - case jump_n: - EXTRACT_NUMBER (mcnt, p + 2); - DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); - - /* Originally, this is how many times we CAN jump. */ - if (mcnt) - { - mcnt--; - STORE_NUMBER (p + 2, mcnt); - goto unconditional_jump; - } - /* If don't have to jump any more, skip over the rest of command. */ - else - p += 4; - break; - - case set_number_at: - { - DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); - - EXTRACT_NUMBER_AND_INCR (mcnt, p); - p1 = p + mcnt; - EXTRACT_NUMBER_AND_INCR (mcnt, p); - DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); - STORE_NUMBER (p1, mcnt); - break; - } - - case wordbound: - DEBUG_PRINT1 ("EXECUTING wordbound.\n"); - if (AT_WORD_BOUNDARY (d)) - break; - goto fail; - - case notwordbound: - DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); - if (AT_WORD_BOUNDARY (d)) - goto fail; - break; - - case wordbeg: - DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); - if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) - break; - goto fail; - - case wordend: - DEBUG_PRINT1 ("EXECUTING wordend.\n"); - if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) - && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) - break; - goto fail; - -#ifdef emacs - case before_dot: - DEBUG_PRINT1 ("EXECUTING before_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) >= point) - goto fail; - break; - - case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) != point) - goto fail; - break; - - case after_dot: - DEBUG_PRINT1 ("EXECUTING after_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) <= point) - goto fail; - break; -#if 0 /* not emacs19 */ - case at_dot: - DEBUG_PRINT1 ("EXECUTING at_dot.\n"); - if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point) - goto fail; - break; -#endif /* not emacs19 */ - - case syntaxspec: - DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); - mcnt = *p++; - goto matchsyntax; - - case wordchar: - DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); - mcnt = (int) Sword; - matchsyntax: - PREFETCH (); - /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ - d++; - if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) - goto fail; - SET_REGS_MATCHED (); - break; - - case notsyntaxspec: - DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); - mcnt = *p++; - goto matchnotsyntax; - - case notwordchar: - DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); - mcnt = (int) Sword; - matchnotsyntax: - PREFETCH (); - /* Can't use *d++ here; SYNTAX may be an unsafe macro. */ - d++; - if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) - goto fail; - SET_REGS_MATCHED (); - break; - -#else /* not emacs */ - case wordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); - PREFETCH (); - if (!WORDCHAR_P (d)) - goto fail; - SET_REGS_MATCHED (); - d++; - break; - - case notwordchar: - DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); - PREFETCH (); - if (WORDCHAR_P (d)) - goto fail; - SET_REGS_MATCHED (); - d++; - break; -#endif /* not emacs */ - - default: - abort (); - } - continue; /* Successfully executed one pattern command; keep going. */ - - - /* We goto here if a matching operation fails. */ - fail: - if (!FAIL_STACK_EMPTY ()) - { /* A restart point is known. Restore to that state. */ - DEBUG_PRINT1 ("\nFAIL:\n"); - POP_FAILURE_POINT (d, p, - lowest_active_reg, highest_active_reg, - regstart, regend, reg_info); - - /* If this failure point is a dummy, try the next one. */ - if (!p) - goto fail; - - /* If we failed to the end of the pattern, don't examine *p. */ - assert (p <= pend); - if (p < pend) - { - boolean is_a_jump_n = false; - - /* If failed to a backwards jump that's part of a repetition - loop, need to pop this failure point and use the next one. */ - switch ((re_opcode_t) *p) - { - case jump_n: - is_a_jump_n = true; - case maybe_pop_jump: - case pop_failure_jump: - case jump: - p1 = p + 1; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - - if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) - || (!is_a_jump_n - && (re_opcode_t) *p1 == on_failure_jump)) - goto fail; - break; - default: - /* do nothing */ ; - } - } - - if (d >= string1 && d <= end1) - dend = end_match_1; - } - else - break; /* Matching at this starting point really fails. */ - } /* for (;;) */ - - if (best_regs_set) - goto restore_best_regs; - - FREE_VARIABLES (); - - return -1; /* Failure to match. */ -} /* re_match_2 */ - -/* Subroutine definitions for re_match_2. */ - - -/* We are passed P pointing to a register number after a start_memory. - - Return true if the pattern up to the corresponding stop_memory can - match the empty string, and false otherwise. - - If we find the matching stop_memory, sets P to point to one past its number. - Otherwise, sets P to an undefined byte less than or equal to END. - - We don't handle duplicates properly (yet). */ - -static boolean -group_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; -{ - int mcnt; - /* Point to after the args to the start_memory. */ - unsigned char *p1 = *p + 2; - - while (p1 < end) - { - /* Skip over opcodes that can match nothing, and return true or - false, as appropriate, when we get to one that can't, or to the - matching stop_memory. */ - - switch ((re_opcode_t) *p1) - { - /* Could be either a loop or a series of alternatives. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - - /* If the next operation is not a jump backwards in the - pattern. */ - - if (mcnt >= 0) - { - /* Go through the on_failure_jumps of the alternatives, - seeing if any of the alternatives cannot match nothing. - The last alternative starts with only a jump, - whereas the rest start with on_failure_jump and end - with a jump, e.g., here is the pattern for `a|b|c': - - /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 - /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 - /exactn/1/c - - So, we have to first go through the first (n-1) - alternatives and then deal with the last one separately. */ - - - /* Deal with the first (n-1) alternatives, which start - with an on_failure_jump (see above) that jumps to right - past a jump_past_alt. */ - - while ((re_opcode_t) p1[mcnt-3] == jump_past_alt) - { - /* `mcnt' holds how many bytes long the alternative - is, including the ending `jump_past_alt' and - its number. */ - - if (!alt_match_null_string_p (p1, p1 + mcnt - 3, - reg_info)) - return false; - - /* Move to right after this alternative, including the - jump_past_alt. */ - p1 += mcnt; - - /* Break if it's the beginning of an n-th alternative - that doesn't begin with an on_failure_jump. */ - if ((re_opcode_t) *p1 != on_failure_jump) - break; - - /* Still have to check that it's not an n-th - alternative that starts with an on_failure_jump. */ - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if ((re_opcode_t) p1[mcnt-3] != jump_past_alt) - { - /* Get to the beginning of the n-th alternative. */ - p1 -= 3; - break; - } - } - - /* Deal with the last alternative: go back and get number - of the `jump_past_alt' just before it. `mcnt' contains - the length of the alternative. */ - EXTRACT_NUMBER (mcnt, p1 - 2); - - if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info)) - return false; - - p1 += mcnt; /* Get past the n-th alternative. */ - } /* if mcnt > 0 */ - break; - - - case stop_memory: - assert (p1[1] == **p); - *p = p1 + 2; - return true; - - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } - } /* while p1 < end */ - - return false; -} /* group_match_null_string_p */ - - -/* Similar to group_match_null_string_p, but doesn't deal with alternatives: - It expects P to be the first byte of a single alternative and END one - byte past the last. The alternative can contain groups. */ - -static boolean -alt_match_null_string_p (p, end, reg_info) - unsigned char *p, *end; - register_info_type *reg_info; -{ - int mcnt; - unsigned char *p1 = p; - - while (p1 < end) - { - /* Skip over opcodes that can match nothing, and break when we get - to one that can't. */ - - switch ((re_opcode_t) *p1) - { - /* It's a loop. */ - case on_failure_jump: - p1++; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - break; - - default: - if (!common_op_match_null_string_p (&p1, end, reg_info)) - return false; - } - } /* while p1 < end */ - - return true; -} /* alt_match_null_string_p */ - - -/* Deals with the ops common to group_match_null_string_p and - alt_match_null_string_p. - - Sets P to one after the op and its arguments, if any. */ - -static boolean -common_op_match_null_string_p (p, end, reg_info) - unsigned char **p, *end; - register_info_type *reg_info; -{ - int mcnt; - boolean ret; - int reg_no; - unsigned char *p1 = *p; - - switch ((re_opcode_t) *p1++) - { - case no_op: - case begline: - case endline: - case begbuf: - case endbuf: - case wordbeg: - case wordend: - case wordbound: - case notwordbound: -#ifdef emacs - case before_dot: - case at_dot: - case after_dot: -#endif - break; - - case start_memory: - reg_no = *p1; - assert (reg_no > 0 && reg_no <= MAX_REGNUM); - ret = group_match_null_string_p (&p1, end, reg_info); - - /* Have to set this here in case we're checking a group which - contains a group and a back reference to it. */ - - if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) - REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; - - if (!ret) - return false; - break; - - /* If this is an optimized succeed_n for zero times, make the jump. */ - case jump: - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - if (mcnt >= 0) - p1 += mcnt; - else - return false; - break; - - case succeed_n: - /* Get to the number of times to succeed. */ - p1 += 2; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - - if (mcnt == 0) - { - p1 -= 4; - EXTRACT_NUMBER_AND_INCR (mcnt, p1); - p1 += mcnt; - } - else - return false; - break; - - case duplicate: - if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) - return false; - break; - - case set_number_at: - p1 += 4; - - default: - /* All other opcodes mean we cannot match the empty string. */ - return false; - } - - *p = p1; - return true; -} /* common_op_match_null_string_p */ - - -/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN - bytes; nonzero otherwise. */ - -static int -bcmp_translate (s1, s2, len, translate) - unsigned char *s1, *s2; - register int len; - char *translate; -{ - register unsigned char *p1 = s1, *p2 = s2; - while (len) - { - if (translate[*p1++] != translate[*p2++]) return 1; - len--; - } - return 0; -} - -/* Entry points for GNU code. */ - -/* re_compile_pattern is the GNU regular expression compiler: it - compiles PATTERN (of length SIZE) and puts the result in BUFP. - Returns 0 if the pattern was valid, otherwise an error string. - - Assumes the `allocated' (and perhaps `buffer') and `translate' fields - are set in BUFP on entry. - - We call regex_compile to do the actual compilation. */ - -const char * -re_compile_pattern (pattern, length, bufp) - const char *pattern; - int length; - struct re_pattern_buffer *bufp; -{ - reg_errcode_t ret; - - /* GNU code is written to assume at least RE_NREGS registers will be set - (and at least one extra will be -1). */ - bufp->regs_allocated = REGS_UNALLOCATED; - - /* And GNU code determines whether or not to get register information - by passing null for the REGS argument to re_match, etc., not by - setting no_sub. */ - bufp->no_sub = 0; - - /* Match anchors at newline. */ - bufp->newline_anchor = 1; - - ret = regex_compile (pattern, length, re_syntax_options, bufp); - - return re_error_msg[(int) ret]; -} - -/* Entry points compatible with 4.2 BSD regex library. We don't define - them if this is an Emacs or POSIX compilation. */ - -#if !defined (emacs) && !defined (_POSIX_SOURCE) - -/* BSD has one and only one pattern buffer. */ -static struct re_pattern_buffer re_comp_buf; - -char * -re_comp (s) - const char *s; -{ - reg_errcode_t ret; - - if (!s) - { - if (!re_comp_buf.buffer) - return "No previous regular expression"; - return 0; - } - - if (!re_comp_buf.buffer) - { - re_comp_buf.buffer = (unsigned char *) malloc (200); - if (re_comp_buf.buffer == NULL) - return "Memory exhausted"; - re_comp_buf.allocated = 200; - - re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); - if (re_comp_buf.fastmap == NULL) - return "Memory exhausted"; - } - - /* Since `re_exec' always passes NULL for the `regs' argument, we - don't need to initialize the pattern buffer fields which affect it. */ - - /* Match anchors at newlines. */ - re_comp_buf.newline_anchor = 1; - - ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); - - /* Yes, we're discarding `const' here. */ - return (char *) re_error_msg[(int) ret]; -} - - -int -re_exec (s) - const char *s; -{ - const int len = strlen (s); - return - 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); -} -#endif /* not emacs and not _POSIX_SOURCE */ - -/* POSIX.2 functions. Don't define these for Emacs. */ - -#ifndef emacs - -/* regcomp takes a regular expression as a string and compiles it. - - PREG is a regex_t *. We do not expect any fields to be initialized, - since POSIX says we shouldn't. Thus, we set - - `buffer' to the compiled pattern; - `used' to the length of the compiled pattern; - `syntax' to RE_SYNTAX_POSIX_EXTENDED if the - REG_EXTENDED bit in CFLAGS is set; otherwise, to - RE_SYNTAX_POSIX_BASIC; - `newline_anchor' to REG_NEWLINE being set in CFLAGS; - `fastmap' and `fastmap_accurate' to zero; - `re_nsub' to the number of subexpressions in PATTERN. - - PATTERN is the address of the pattern string. - - CFLAGS is a series of bits which affect compilation. - - If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we - use POSIX basic syntax. - - If REG_NEWLINE is set, then . and [^...] don't match newline. - Also, regexec will try a match beginning after every newline. - - If REG_ICASE is set, then we considers upper- and lowercase - versions of letters to be equivalent when matching. - - If REG_NOSUB is set, then when PREG is passed to regexec, that - routine will report only success or failure, and nothing about the - registers. - - It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for - the return codes and their meanings.) */ - -int -regcomp (preg, pattern, cflags) - regex_t *preg; - const char *pattern; - int cflags; -{ - reg_errcode_t ret; - unsigned syntax - = (cflags & REG_EXTENDED) ? - RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; - - /* regex_compile will allocate the space for the compiled pattern. */ - preg->buffer = 0; - preg->allocated = 0; - preg->used = 0; - - /* Don't bother to use a fastmap when searching. This simplifies the - REG_NEWLINE case: if we used a fastmap, we'd have to put all the - characters after newlines into the fastmap. This way, we just try - every character. */ - preg->fastmap = 0; - - if (cflags & REG_ICASE) - { - unsigned i; - - preg->translate = (char *) malloc (CHAR_SET_SIZE); - if (preg->translate == NULL) - return (int) REG_ESPACE; - - /* Map uppercase characters to corresponding lowercase ones. */ - for (i = 0; i < CHAR_SET_SIZE; i++) - preg->translate[i] = ISUPPER (i) ? tolower (i) : i; - } - else - preg->translate = NULL; - - /* If REG_NEWLINE is set, newlines are treated differently. */ - if (cflags & REG_NEWLINE) - { /* REG_NEWLINE implies neither . nor [^...] match newline. */ - syntax &= ~RE_DOT_NEWLINE; - syntax |= RE_HAT_LISTS_NOT_NEWLINE; - /* It also changes the matching behavior. */ - preg->newline_anchor = 1; - } - else - preg->newline_anchor = 0; - - preg->no_sub = !!(cflags & REG_NOSUB); - - /* POSIX says a null character in the pattern terminates it, so we - can use strlen here in compiling the pattern. */ - ret = regex_compile (pattern, strlen (pattern), syntax, preg); - - /* POSIX doesn't distinguish between an unmatched open-group and an - unmatched close-group: both are REG_EPAREN. */ - if (ret == REG_ERPAREN) ret = REG_EPAREN; - - return (int) ret; -} - - -/* regexec searches for a given pattern, specified by PREG, in the - string STRING. - - If NMATCH is zero or REG_NOSUB was set in the cflags argument to - `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at - least NMATCH elements, and we set them to the offsets of the - corresponding matched substrings. - - EFLAGS specifies `execution flags' which affect matching: if - REG_NOTBOL is set, then ^ does not match at the beginning of the - string; if REG_NOTEOL is set, then $ does not match at the end. - - We return 0 if we find a match and REG_NOMATCH if not. */ - -int -regexec (preg, string, nmatch, pmatch, eflags) - const regex_t *preg; - const char *string; - size_t nmatch; - regmatch_t pmatch[]; - int eflags; -{ - int ret; - struct re_registers regs; - regex_t private_preg; - int len = strlen (string); - boolean want_reg_info = !preg->no_sub && nmatch > 0; - - private_preg = *preg; - - private_preg.not_bol = !!(eflags & REG_NOTBOL); - private_preg.not_eol = !!(eflags & REG_NOTEOL); - - /* The user has told us exactly how many registers to return - information about, via `nmatch'. We have to pass that on to the - matching routines. */ - private_preg.regs_allocated = REGS_FIXED; - - if (want_reg_info) - { - regs.num_regs = nmatch; - regs.start = TALLOC (nmatch, regoff_t); - regs.end = TALLOC (nmatch, regoff_t); - if (regs.start == NULL || regs.end == NULL) - return (int) REG_NOMATCH; - } - - /* Perform the searching operation. */ - ret = re_search (&private_preg, string, len, - /* start: */ 0, /* range: */ len, - want_reg_info ? ®s : (struct re_registers *) 0); - - /* Copy the register information to the POSIX structure. */ - if (want_reg_info) - { - if (ret >= 0) - { - unsigned r; - - for (r = 0; r < nmatch; r++) - { - pmatch[r].rm_so = regs.start[r]; - pmatch[r].rm_eo = regs.end[r]; - } - } - - /* If we needed the temporary register info, free the space now. */ - free (regs.start); - free (regs.end); - } - - /* We want zero return to mean success, unlike `re_search'. */ - return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; -} - - -/* Returns a message corresponding to an error code, ERRCODE, returned - from either regcomp or regexec. We don't use PREG here. */ - -size_t -regerror (errcode, preg, errbuf, errbuf_size) - int errcode; - const regex_t *preg; - char *errbuf; - size_t errbuf_size; -{ - const char *msg; - size_t msg_size; - - if (errcode < 0 - || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) - /* Only error codes returned by the rest of the code should be passed - to this routine. If we are given anything else, or if other regex - code generates an invalid error code, then the program has a bug. - Dump core so we can fix it. */ - abort (); - - msg = re_error_msg[errcode]; - - /* POSIX doesn't require that we do anything in this case, but why - not be nice. */ - if (! msg) - msg = "Success"; - - msg_size = strlen (msg) + 1; /* Includes the null. */ - - if (errbuf_size != 0) - { - if (msg_size > errbuf_size) - { - strncpy (errbuf, msg, errbuf_size - 1); - errbuf[errbuf_size - 1] = 0; - } - else - strcpy (errbuf, msg); - } - - return msg_size; -} - - -/* Free dynamically allocated space used by PREG. */ - -void -regfree (preg) - regex_t *preg; -{ - if (preg->buffer != NULL) - free (preg->buffer); - preg->buffer = NULL; - - preg->allocated = 0; - preg->used = 0; - - if (preg->fastmap != NULL) - free (preg->fastmap); - preg->fastmap = NULL; - preg->fastmap_accurate = 0; - - if (preg->translate != NULL) - free (preg->translate); - preg->translate = NULL; -} - -#endif /* not emacs */ - -/* -Local variables: -make-backup-files: t -version-control: t -trim-versions-without-asking: nil -End: -*/ diff --git a/gnu/usr.bin/diff/regex.h b/gnu/usr.bin/diff/regex.h deleted file mode 100644 index a495005ce936..000000000000 --- a/gnu/usr.bin/diff/regex.h +++ /dev/null @@ -1,490 +0,0 @@ -/* Definitions for data structures and routines for the regular - expression library, version 0.12. - - Copyright (C) 1985, 89, 90, 91, 92, 1993 Free Software Foundation, Inc. - - This program 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. - - This program 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; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef __REGEXP_LIBRARY_H__ -#define __REGEXP_LIBRARY_H__ - -/* POSIX says that must be included (by the caller) before - . */ - -#ifdef VMS -/* VMS doesn't have `size_t' in , even though POSIX says it - should be there. */ -#include -#endif - - -/* The following bits are used to determine the regexp syntax we - recognize. The set/not-set meanings are chosen so that Emacs syntax - remains the value 0. The bits are given in alphabetical order, and - the definitions shifted by one from the previous bit; thus, when we - add or remove a bit, only one other definition need change. */ -typedef unsigned reg_syntax_t; - -/* If this bit is not set, then \ inside a bracket expression is literal. - If set, then such a \ quotes the following character. */ -#define RE_BACKSLASH_ESCAPE_IN_LISTS (1) - -/* If this bit is not set, then + and ? are operators, and \+ and \? are - literals. - If set, then \+ and \? are operators and + and ? are literals. */ -#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) - -/* If this bit is set, then character classes are supported. They are: - [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], - [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. - If not set, then character classes are not supported. */ -#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) - -/* If this bit is set, then ^ and $ are always anchors (outside bracket - expressions, of course). - If this bit is not set, then it depends: - ^ is an anchor if it is at the beginning of a regular - expression or after an open-group or an alternation operator; - $ is an anchor if it is at the end of a regular expression, or - before a close-group or an alternation operator. - - This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because - POSIX draft 11.2 says that * etc. in leading positions is undefined. - We already implemented a previous draft which made those constructs - invalid, though, so we haven't changed the code back. */ -#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) - -/* If this bit is set, then special characters are always special - regardless of where they are in the pattern. - If this bit is not set, then special characters are special only in - some contexts; otherwise they are ordinary. Specifically, - * + ? and intervals are only special when not after the beginning, - open-group, or alternation operator. */ -#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) - -/* If this bit is set, then *, +, ?, and { cannot be first in an re or - immediately after an alternation or begin-group operator. */ -#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) - -/* If this bit is set, then . matches newline. - If not set, then it doesn't. */ -#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) - -/* If this bit is set, then . doesn't match NUL. - If not set, then it does. */ -#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) - -/* If this bit is set, nonmatching lists [^...] do not match newline. - If not set, they do. */ -#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) - -/* If this bit is set, either \{...\} or {...} defines an - interval, depending on RE_NO_BK_BRACES. - If not set, \{, \}, {, and } are literals. */ -#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) - -/* If this bit is set, +, ? and | aren't recognized as operators. - If not set, they are. */ -#define RE_LIMITED_OPS (RE_INTERVALS << 1) - -/* If this bit is set, newline is an alternation operator. - If not set, newline is literal. */ -#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) - -/* If this bit is set, then `{...}' defines an interval, and \{ and \} - are literals. - If not set, then `\{...\}' defines an interval. */ -#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) - -/* If this bit is set, (...) defines a group, and \( and \) are literals. - If not set, \(...\) defines a group, and ( and ) are literals. */ -#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) - -/* If this bit is set, then \ matches . - If not set, then \ is a back-reference. */ -#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) - -/* If this bit is set, then | is an alternation operator, and \| is literal. - If not set, then \| is an alternation operator, and | is literal. */ -#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) - -/* If this bit is set, then an ending range point collating higher - than the starting range point, as in [z-a], is invalid. - If not set, then when ending range point collates higher than the - starting range point, the range is ignored. */ -#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) - -/* If this bit is set, then an unmatched ) is ordinary. - If not set, then an unmatched ) is invalid. */ -#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) - -/* This global variable defines the particular regexp syntax to use (for - some interfaces). When a regexp is compiled, the syntax used is - stored in the pattern buffer, so changing this does not affect - already-compiled regexps. */ -extern reg_syntax_t re_syntax_options; - -/* Define combinations of the above bits for the standard possibilities. - (The [[[ comments delimit what gets put into the Texinfo file, so - don't delete them!) */ -/* [[[begin syntaxes]]] */ -#define RE_SYNTAX_EMACS 0 - -#define RE_SYNTAX_AWK \ - (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ - | RE_NO_BK_PARENS | RE_NO_BK_REFS \ - | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ - | RE_UNMATCHED_RIGHT_PAREN_ORD) - -#define RE_SYNTAX_POSIX_AWK \ - (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) - -#define RE_SYNTAX_GREP \ - (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ - | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ - | RE_NEWLINE_ALT) - -#define RE_SYNTAX_EGREP \ - (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ - | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ - | RE_NO_BK_VBAR) - -#define RE_SYNTAX_POSIX_EGREP \ - (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) - -/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ -#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC - -#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC - -/* Syntax bits common to both basic and extended POSIX regex syntax. */ -#define _RE_SYNTAX_POSIX_COMMON \ - (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ - | RE_INTERVALS | RE_NO_EMPTY_RANGES) - -#define RE_SYNTAX_POSIX_BASIC \ - (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) - -/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes - RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this - isn't minimal, since other operators, such as \`, aren't disabled. */ -#define RE_SYNTAX_POSIX_MINIMAL_BASIC \ - (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) - -#define RE_SYNTAX_POSIX_EXTENDED \ - (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ - | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ - | RE_UNMATCHED_RIGHT_PAREN_ORD) - -/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS - replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ -#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ - (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ - | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ - | RE_NO_BK_PARENS | RE_NO_BK_REFS \ - | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) -/* [[[end syntaxes]]] */ - -/* Maximum number of duplicates an interval can allow. Some systems - (erroneously) define this in other header files, but we want our - value, so remove any previous define. */ -#ifdef RE_DUP_MAX -#undef RE_DUP_MAX -#endif -#define RE_DUP_MAX ((1 << 15) - 1) - - -/* POSIX `cflags' bits (i.e., information for `regcomp'). */ - -/* If this bit is set, then use extended regular expression syntax. - If not set, then use basic regular expression syntax. */ -#define REG_EXTENDED 1 - -/* If this bit is set, then ignore case when matching. - If not set, then case is significant. */ -#define REG_ICASE (REG_EXTENDED << 1) - -/* If this bit is set, then anchors do not match at newline - characters in the string. - If not set, then anchors do match at newlines. */ -#define REG_NEWLINE (REG_ICASE << 1) - -/* If this bit is set, then report only success or fail in regexec. - If not set, then returns differ between not matching and errors. */ -#define REG_NOSUB (REG_NEWLINE << 1) - - -/* POSIX `eflags' bits (i.e., information for regexec). */ - -/* If this bit is set, then the beginning-of-line operator doesn't match - the beginning of the string (presumably because it's not the - beginning of a line). - If not set, then the beginning-of-line operator does match the - beginning of the string. */ -#define REG_NOTBOL 1 - -/* Like REG_NOTBOL, except for the end-of-line. */ -#define REG_NOTEOL (1 << 1) - - -/* If any error codes are removed, changed, or added, update the - `re_error_msg' table in regex.c. */ -typedef enum -{ - REG_NOERROR = 0, /* Success. */ - REG_NOMATCH, /* Didn't find a match (for regexec). */ - - /* POSIX regcomp return error codes. (In the order listed in the - standard.) */ - REG_BADPAT, /* Invalid pattern. */ - REG_ECOLLATE, /* Not implemented. */ - REG_ECTYPE, /* Invalid character class name. */ - REG_EESCAPE, /* Trailing backslash. */ - REG_ESUBREG, /* Invalid back reference. */ - REG_EBRACK, /* Unmatched left bracket. */ - REG_EPAREN, /* Parenthesis imbalance. */ - REG_EBRACE, /* Unmatched \{. */ - REG_BADBR, /* Invalid contents of \{\}. */ - REG_ERANGE, /* Invalid range end. */ - REG_ESPACE, /* Ran out of memory. */ - REG_BADRPT, /* No preceding re for repetition op. */ - - /* Error codes we've added. */ - REG_EEND, /* Premature end. */ - REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ - REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ -} reg_errcode_t; - -/* This data structure represents a compiled pattern. Before calling - the pattern compiler, the fields `buffer', `allocated', `fastmap', - `translate', and `no_sub' can be set. After the pattern has been - compiled, the `re_nsub' field is available. All other fields are - private to the regex routines. */ - -struct re_pattern_buffer -{ -/* [[[begin pattern_buffer]]] */ - /* Space that holds the compiled pattern. It is declared as - `unsigned char *' because its elements are - sometimes used as array indexes. */ - unsigned char *buffer; - - /* Number of bytes to which `buffer' points. */ - unsigned long allocated; - - /* Number of bytes actually used in `buffer'. */ - unsigned long used; - - /* Syntax setting with which the pattern was compiled. */ - reg_syntax_t syntax; - - /* Pointer to a fastmap, if any, otherwise zero. re_search uses - the fastmap, if there is one, to skip over impossible - starting points for matches. */ - char *fastmap; - - /* Either a translate table to apply to all characters before - comparing them, or zero for no translation. The translation - is applied to a pattern when it is compiled and to a string - when it is matched. */ - char *translate; - - /* Number of subexpressions found by the compiler. */ - size_t re_nsub; - - /* Zero if this pattern cannot match the empty string, one else. - Well, in truth it's used only in `re_search_2', to see - whether or not we should use the fastmap, so we don't set - this absolutely perfectly; see `re_compile_fastmap' (the - `duplicate' case). */ - unsigned can_be_null : 1; - - /* If REGS_UNALLOCATED, allocate space in the `regs' structure - for `max (RE_NREGS, re_nsub + 1)' groups. - If REGS_REALLOCATE, reallocate space if necessary. - If REGS_FIXED, use what's there. */ -#define REGS_UNALLOCATED 0 -#define REGS_REALLOCATE 1 -#define REGS_FIXED 2 - unsigned regs_allocated : 2; - - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ - unsigned fastmap_accurate : 1; - - /* If set, `re_match_2' does not return information about - subexpressions. */ - unsigned no_sub : 1; - - /* If set, a beginning-of-line anchor doesn't match at the - beginning of the string. */ - unsigned not_bol : 1; - - /* Similarly for an end-of-line anchor. */ - unsigned not_eol : 1; - - /* If true, an anchor at a newline matches. */ - unsigned newline_anchor : 1; - -/* [[[end pattern_buffer]]] */ -}; - -typedef struct re_pattern_buffer regex_t; - - -/* search.c (search_buffer) in Emacs needs this one opcode value. It is - defined both in `regex.c' and here. */ -#define RE_EXACTN_VALUE 1 - -/* Type for byte offsets within the string. POSIX mandates this. */ -typedef int regoff_t; - - -/* This is the structure we store register match data in. See - regex.texinfo for a full description of what registers match. */ -struct re_registers -{ - unsigned num_regs; - regoff_t *start; - regoff_t *end; -}; - - -/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, - `re_match_2' returns information about at least this many registers - the first time a `regs' structure is passed. */ -#ifndef RE_NREGS -#define RE_NREGS 30 -#endif - - -/* POSIX specification for registers. Aside from the different names than - `re_registers', POSIX uses an array of structures, instead of a - structure of arrays. */ -typedef struct -{ - regoff_t rm_so; /* Byte offset from string's start to substring's start. */ - regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ -} regmatch_t; - -/* Declarations for routines. */ - -/* To avoid duplicating every routine declaration -- once with a - prototype (if we are ANSI), and once without (if we aren't) -- we - use the following macro to declare argument types. This - unfortunately clutters up the declarations a bit, but I think it's - worth it. */ - -#if __STDC__ - -#define _RE_ARGS(args) args - -#else /* not __STDC__ */ - -#define _RE_ARGS(args) () - -#endif /* not __STDC__ */ - -/* Sets the current default syntax to SYNTAX, and return the old syntax. - You can also simply assign to the `re_syntax_options' variable. */ -extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); - -/* Compile the regular expression PATTERN, with length LENGTH - and syntax given by the global `re_syntax_options', into the buffer - BUFFER. Return NULL if successful, and an error string if not. */ -extern const char *re_compile_pattern - _RE_ARGS ((const char *pattern, int length, - struct re_pattern_buffer *buffer)); - - -/* Compile a fastmap for the compiled pattern in BUFFER; used to - accelerate searches. Return 0 if successful and -2 if was an - internal error. */ -extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); - - -/* Search in the string STRING (with length LENGTH) for the pattern - compiled into BUFFER. Start searching at position START, for RANGE - characters. Return the starting position of the match, -1 for no - match, or -2 for an internal error. Also return register - information in REGS (if REGS and BUFFER->no_sub are nonzero). */ -extern int re_search - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, int range, struct re_registers *regs)); - - -/* Like `re_search', but search in the concatenation of STRING1 and - STRING2. Also, stop searching at index START + STOP. */ -extern int re_search_2 - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, int range, struct re_registers *regs, int stop)); - - -/* Like `re_search', but return how many characters in STRING the regexp - in BUFFER matched, starting at position START. */ -extern int re_match - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, - int length, int start, struct re_registers *regs)); - - -/* Relates to `re_match' as `re_search_2' relates to `re_search'. */ -extern int re_match_2 - _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, - int length1, const char *string2, int length2, - int start, struct re_registers *regs, int stop)); - - -/* Set REGS to hold NUM_REGS registers, storing them in STARTS and - ENDS. Subsequent matches using BUFFER and REGS will use this memory - for recording register information. STARTS and ENDS must be - allocated with malloc, and must each be at least `NUM_REGS * sizeof - (regoff_t)' bytes long. - - If NUM_REGS == 0, then subsequent matches should allocate their own - register data. - - Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ -extern void re_set_registers - _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, - unsigned num_regs, regoff_t *starts, regoff_t *ends)); - -/* 4.2 bsd compatibility. */ -extern char *re_comp _RE_ARGS ((const char *)); -extern int re_exec _RE_ARGS ((const char *)); - -/* POSIX compatibility. */ -extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags)); -extern int regexec - _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch, - regmatch_t pmatch[], int eflags)); -extern size_t regerror - _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf, - size_t errbuf_size)); -extern void regfree _RE_ARGS ((regex_t *preg)); - -#endif /* not __REGEXP_LIBRARY_H__ */ - -/* -Local variables: -make-backup-files: t -version-control: t -trim-versions-without-asking: nil -End: -*/ diff --git a/gnu/usr.bin/diff/sdiff.c b/gnu/usr.bin/diff/sdiff.c deleted file mode 100644 index b64f1d038365..000000000000 --- a/gnu/usr.bin/diff/sdiff.c +++ /dev/null @@ -1,1180 +0,0 @@ -/* SDIFF -- interactive merge front end to diff - Copyright (C) 1992, 1993, 1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* GNU SDIFF was written by Thomas Lord. */ - -#include "system.h" -#include -#include -#include "getopt.h" - -/* Size of chunks read from files which must be parsed into lines. */ -#define SDIFF_BUFSIZE ((size_t) 65536) - -/* Default name of the diff program */ -#ifndef DIFF_PROGRAM -#define DIFF_PROGRAM "/usr/bin/diff" -#endif - -/* Users' editor of nonchoice */ -#ifndef DEFAULT_EDITOR_PROGRAM -#define DEFAULT_EDITOR_PROGRAM "ed" -#endif - -extern char version_string[]; -static char const *program_name; -static char const *diffbin = DIFF_PROGRAM; -static char const *edbin = DEFAULT_EDITOR_PROGRAM; -static char const **diffargv; - -static char *tmpname; -static int volatile tmpmade; - -#if HAVE_FORK -static pid_t volatile diffpid; -#endif - -struct line_filter; - -static FILE *ck_fopen PARAMS((char const *, char const *)); -static RETSIGTYPE catchsig PARAMS((int)); -static VOID *xmalloc PARAMS((size_t)); -static char const *expand_name PARAMS((char *, int, char const *)); -static int edit PARAMS((struct line_filter *, int, struct line_filter *, int, FILE*)); -static int interact PARAMS((struct line_filter *, struct line_filter *, struct line_filter *, FILE*)); -static int lf_snarf PARAMS((struct line_filter *, char *, size_t)); -static int skip_white PARAMS((void)); -static size_t ck_fread PARAMS((char *, size_t, FILE *)); -static size_t lf_refill PARAMS((struct line_filter *)); -static void checksigs PARAMS((void)); -static void ck_fclose PARAMS((FILE *)); -static void ck_fflush PARAMS((FILE *)); -static void ck_fwrite PARAMS((char const *, size_t, FILE *)); -static void cleanup PARAMS((void)); -static void diffarg PARAMS((char const *)); -static void execdiff PARAMS((void)); -static void exiterr PARAMS((void)); -static void fatal PARAMS((char const *)); -static void flush_line PARAMS((void)); -static void give_help PARAMS((void)); -static void lf_copy PARAMS((struct line_filter *, int, FILE *)); -static void lf_init PARAMS((struct line_filter *, FILE *)); -static void lf_skip PARAMS((struct line_filter *, int)); -static void perror_fatal PARAMS((char const *)); -static void trapsigs PARAMS((void)); -static void try_help PARAMS((char const *)); -static void untrapsig PARAMS((int)); -static void usage PARAMS((void)); - -/* this lossage until the gnu libc conquers the universe */ -#if HAVE_TMPNAM -#define private_tempnam() tmpnam ((char *) 0) -#else -#ifndef PVT_tmpdir -#define PVT_tmpdir "/tmp" -#endif -#ifndef TMPDIR_ENV -#define TMPDIR_ENV "TMPDIR" -#endif -static char *private_tempnam PARAMS((void)); -static int exists PARAMS((char const *)); -#endif -static int diraccess PARAMS((char const *)); - -/* Options: */ - -/* name of output file if -o spec'd */ -static char *out_file; - -/* do not print common lines if true, set by -s option */ -static int suppress_common_flag; - -static struct option const longopts[] = -{ - {"ignore-blank-lines", 0, 0, 'B'}, - {"speed-large-files", 0, 0, 'H'}, - {"ignore-matching-lines", 1, 0, 'I'}, - {"ignore-all-space", 0, 0, 'W'}, /* swap W and w for historical reasons */ - {"text", 0, 0, 'a'}, - {"ignore-space-change", 0, 0, 'b'}, - {"minimal", 0, 0, 'd'}, - {"ignore-case", 0, 0, 'i'}, - {"left-column", 0, 0, 'l'}, - {"output", 1, 0, 'o'}, - {"suppress-common-lines", 0, 0, 's'}, - {"expand-tabs", 0, 0, 't'}, - {"width", 1, 0, 'w'}, - {"version", 0, 0, 'v'}, - {"help", 0, 0, 129}, - {0, 0, 0, 0} -}; - -static void -try_help (reason) - char const *reason; -{ - if (reason) - fprintf (stderr, "%s: %s\n", program_name, reason); - fprintf (stderr, "%s: Try `%s --help' for more information.\n", - program_name, program_name); - exit (2); -} - -static void -usage () -{ - printf ("Usage: %s [OPTIONS]... FILE1 FILE2\n\n", program_name); - printf ("%s", "\ - -o FILE --output=FILE Operate interactively, sending output to FILE.\n\n"); - printf ("%s", "\ - -i --ignore-case Consider upper- and lower-case to be the same.\n\ - -W --ignore-all-space Ignore all white space.\n\ - -b --ignore-space-change Ignore changes in the amount of white space.\n\ - -B --ignore-blank-lines Ignore changes whose lines are all blank.\n\ - -I RE --ignore-matching-lines=RE Ignore changes whose lines all match RE.\n\ - -a --text Treat all files as text.\n\n"); - printf ("%s", "\ - -w NUM --width=NUM Output at most NUM (default 130) characters per line.\n\ - -l --left-column Output only the left column of common lines.\n\ - -s --suppress-common-lines Do not output common lines.\n\n"); - printf ("\ - -t --expand-tabs Expand tabs to spaces in output.\n\n"); - printf ("%s", "\ - -d --minimal Try hard to find a smaller set of changes.\n\ - -H --speed-large-files Assume large files and many scattered small changes.\n\n"); - printf ("%s", "\ - -v --version Output version info.\n\ - --help Output this help.\n\n\ -If FILE1 or FILE2 is `-', read standard input.\n"); -} - -static void -cleanup () -{ -#if HAVE_FORK - if (0 < diffpid) - kill (diffpid, SIGPIPE); -#endif - if (tmpmade) - unlink (tmpname); -} - -static void -exiterr () -{ - cleanup (); - untrapsig (0); - checksigs (); - exit (2); -} - -static void -fatal (msg) - char const *msg; -{ - fprintf (stderr, "%s: %s\n", program_name, msg); - exiterr (); -} - -static void -perror_fatal (msg) - char const *msg; -{ - int e = errno; - checksigs (); - fprintf (stderr, "%s: ", program_name); - errno = e; - perror (msg); - exiterr (); -} - - -/* malloc freely or DIE! */ -static VOID * -xmalloc (size) - size_t size; -{ - VOID *r = (VOID *) malloc (size); - if (!r) - fatal ("memory exhausted"); - return r; -} - -static FILE * -ck_fopen (fname, type) - char const *fname, *type; -{ - FILE *r = fopen (fname, type); - if (!r) - perror_fatal (fname); - return r; -} - -static void -ck_fclose (f) - FILE *f; -{ - if (fclose (f)) - perror_fatal ("input/output error"); -} - -static size_t -ck_fread (buf, size, f) - char *buf; - size_t size; - FILE *f; -{ - size_t r = fread (buf, sizeof (char), size, f); - if (r == 0 && ferror (f)) - perror_fatal ("input error"); - return r; -} - -static void -ck_fwrite (buf, size, f) - char const *buf; - size_t size; - FILE *f; -{ - if (fwrite (buf, sizeof (char), size, f) != size) - perror_fatal ("output error"); -} - -static void -ck_fflush (f) - FILE *f; -{ - if (fflush (f) != 0) - perror_fatal ("output error"); -} - -static char const * -expand_name (name, is_dir, other_name) - char *name; - int is_dir; - char const *other_name; -{ - if (strcmp (name, "-") == 0) - fatal ("cannot interactively merge standard input"); - if (!is_dir) - return name; - else - { - /* Yield NAME/BASE, where BASE is OTHER_NAME's basename. */ - char const *p = filename_lastdirchar (other_name); - char const *base = p ? p+1 : other_name; - size_t namelen = strlen (name), baselen = strlen (base); - char *r = xmalloc (namelen + baselen + 2); - memcpy (r, name, namelen); - r[namelen] = '/'; - memcpy (r + namelen + 1, base, baselen + 1); - return r; - } -} - - - -struct line_filter { - FILE *infile; - char *bufpos; - char *buffer; - char *buflim; -}; - -static void -lf_init (lf, infile) - struct line_filter *lf; - FILE *infile; -{ - lf->infile = infile; - lf->bufpos = lf->buffer = lf->buflim = xmalloc (SDIFF_BUFSIZE + 1); - lf->buflim[0] = '\n'; -} - -/* Fill an exhausted line_filter buffer from its INFILE */ -static size_t -lf_refill (lf) - struct line_filter *lf; -{ - size_t s = ck_fread (lf->buffer, SDIFF_BUFSIZE, lf->infile); - lf->bufpos = lf->buffer; - lf->buflim = lf->buffer + s; - lf->buflim[0] = '\n'; - checksigs (); - return s; -} - -/* Advance LINES on LF's infile, copying lines to OUTFILE */ -static void -lf_copy (lf, lines, outfile) - struct line_filter *lf; - int lines; - FILE *outfile; -{ - char *start = lf->bufpos; - - while (lines) - { - lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); - if (! lf->bufpos) - { - ck_fwrite (start, lf->buflim - start, outfile); - if (! lf_refill (lf)) - return; - start = lf->bufpos; - } - else - { - --lines; - ++lf->bufpos; - } - } - - ck_fwrite (start, lf->bufpos - start, outfile); -} - -/* Advance LINES on LF's infile without doing output */ -static void -lf_skip (lf, lines) - struct line_filter *lf; - int lines; -{ - while (lines) - { - lf->bufpos = (char *) memchr (lf->bufpos, '\n', lf->buflim - lf->bufpos); - if (! lf->bufpos) - { - if (! lf_refill (lf)) - break; - } - else - { - --lines; - ++lf->bufpos; - } - } -} - -/* Snarf a line into a buffer. Return EOF if EOF, 0 if error, 1 if OK. */ -static int -lf_snarf (lf, buffer, bufsize) - struct line_filter *lf; - char *buffer; - size_t bufsize; -{ - char *start = lf->bufpos; - - for (;;) - { - char *next = (char *) memchr (start, '\n', lf->buflim + 1 - start); - size_t s = next - start; - if (bufsize <= s) - return 0; - memcpy (buffer, start, s); - if (next < lf->buflim) - { - buffer[s] = 0; - lf->bufpos = next + 1; - return 1; - } - if (! lf_refill (lf)) - return s ? 0 : EOF; - buffer += s; - bufsize -= s; - start = next; - } -} - - - -int -main (argc, argv) - int argc; - char *argv[]; -{ - int opt; - char *editor; - char *differ; - - initialize_main (&argc, &argv); - program_name = argv[0]; - - editor = getenv ("EDITOR"); - if (editor) - edbin = editor; - differ = getenv ("DIFF"); - if (differ) - diffbin = differ; - - diffarg ("diff"); - - /* parse command line args */ - while ((opt = getopt_long (argc, argv, "abBdHiI:lo:stvw:W", longopts, 0)) - != EOF) - { - switch (opt) - { - case 'a': - diffarg ("-a"); - break; - - case 'b': - diffarg ("-b"); - break; - - case 'B': - diffarg ("-B"); - break; - - case 'd': - diffarg ("-d"); - break; - - case 'H': - diffarg ("-H"); - break; - - case 'i': - diffarg ("-i"); - break; - - case 'I': - diffarg ("-I"); - diffarg (optarg); - break; - - case 'l': - diffarg ("--left-column"); - break; - - case 'o': - out_file = optarg; - break; - - case 's': - suppress_common_flag = 1; - break; - - case 't': - diffarg ("-t"); - break; - - case 'v': - printf ("sdiff - GNU diffutils version %s\n", version_string); - exit (0); - - case 'w': - diffarg ("-W"); - diffarg (optarg); - break; - - case 'W': - diffarg ("-w"); - break; - - case 129: - usage (); - if (ferror (stdout) || fclose (stdout) != 0) - fatal ("write error"); - exit (0); - - default: - try_help (0); - } - } - - if (argc - optind != 2) - try_help (argc - optind < 2 ? "missing operand" : "extra operand"); - - if (! out_file) - { - /* easy case: diff does everything for us */ - if (suppress_common_flag) - diffarg ("--suppress-common-lines"); - diffarg ("-y"); - diffarg ("--"); - diffarg (argv[optind]); - diffarg (argv[optind + 1]); - diffarg (0); - execdiff (); - } - else - { - FILE *left, *right, *out, *diffout; - int interact_ok; - struct line_filter lfilt; - struct line_filter rfilt; - struct line_filter diff_filt; - int leftdir = diraccess (argv[optind]); - int rightdir = diraccess (argv[optind + 1]); - - if (leftdir && rightdir) - fatal ("both files to be compared are directories"); - - left = ck_fopen (expand_name (argv[optind], leftdir, argv[optind + 1]), "r"); - ; - right = ck_fopen (expand_name (argv[optind + 1], rightdir, argv[optind]), "r"); - out = ck_fopen (out_file, "w"); - - diffarg ("--sdiff-merge-assist"); - diffarg ("--"); - diffarg (argv[optind]); - diffarg (argv[optind + 1]); - diffarg (0); - - trapsigs (); - -#if ! HAVE_FORK - { - size_t cmdsize = 1; - char *p, *command; - int i; - - for (i = 0; diffargv[i]; i++) - cmdsize += 4 * strlen (diffargv[i]) + 3; - command = p = xmalloc (cmdsize); - for (i = 0; diffargv[i]; i++) - { - char const *a = diffargv[i]; - SYSTEM_QUOTE_ARG (p, a); - *p++ = ' '; - } - p[-1] = '\0'; - diffout = popen (command, "r"); - if (!diffout) - perror_fatal (command); - free (command); - } -#else /* HAVE_FORK */ - { - int diff_fds[2]; - - if (pipe (diff_fds) != 0) - perror_fatal ("pipe"); - - diffpid = vfork (); - if (diffpid < 0) - perror_fatal ("fork failed"); - if (!diffpid) - { - signal (SIGINT, SIG_IGN); /* in case user interrupts editor */ - signal (SIGPIPE, SIG_DFL); - - close (diff_fds[0]); - if (diff_fds[1] != STDOUT_FILENO) - { - dup2 (diff_fds[1], STDOUT_FILENO); - close (diff_fds[1]); - } - - execdiff (); - } - - close (diff_fds[1]); - diffout = fdopen (diff_fds[0], "r"); - if (!diffout) - perror_fatal ("fdopen"); - } -#endif /* HAVE_FORK */ - - lf_init (&diff_filt, diffout); - lf_init (&lfilt, left); - lf_init (&rfilt, right); - - interact_ok = interact (&diff_filt, &lfilt, &rfilt, out); - - ck_fclose (left); - ck_fclose (right); - ck_fclose (out); - - { - int wstatus; - -#if ! HAVE_FORK - wstatus = pclose (diffout); -#else - ck_fclose (diffout); - while (waitpid (diffpid, &wstatus, 0) < 0) - if (errno == EINTR) - checksigs (); - else - perror_fatal ("wait failed"); - diffpid = 0; -#endif - - if (tmpmade) - { - unlink (tmpname); - tmpmade = 0; - } - - if (! interact_ok) - exiterr (); - - if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2)) - fatal ("Subsidiary diff failed"); - - untrapsig (0); - checksigs (); - exit (WEXITSTATUS (wstatus)); - } - } - return 0; /* Fool -Wall . . . */ -} - -static void -diffarg (a) - char const *a; -{ - static unsigned diffargs, diffargsmax; - - if (diffargs == diffargsmax) - { - if (! diffargsmax) - { - diffargv = (char const **) xmalloc (sizeof (char)); - diffargsmax = 8; - } - diffargsmax *= 2; - diffargv = (char const **) realloc (diffargv, - diffargsmax * sizeof (char const *)); - if (! diffargv) - fatal ("out of memory"); - } - diffargv[diffargs++] = a; -} - -static void -execdiff () -{ - execvp (diffbin, (char **) diffargv); - write (STDERR_FILENO, diffbin, strlen (diffbin)); - write (STDERR_FILENO, ": not found\n", 12); - _exit (2); -} - - - - -/* Signal handling */ - -#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs)) -static int const sigs[] = { -#ifdef SIGHUP - SIGHUP, -#endif -#ifdef SIGQUIT - SIGQUIT, -#endif -#ifdef SIGTERM - SIGTERM, -#endif -#ifdef SIGXCPU - SIGXCPU, -#endif -#ifdef SIGXFSZ - SIGXFSZ, -#endif - SIGINT, - SIGPIPE -}; - -/* Prefer `sigaction' if it is available, since `signal' can lose signals. */ -#if HAVE_SIGACTION -static struct sigaction initial_action[NUM_SIGS]; -#define initial_handler(i) (initial_action[i].sa_handler) -#else -static RETSIGTYPE (*initial_action[NUM_SIGS]) (); -#define initial_handler(i) (initial_action[i]) -#endif - -static int volatile ignore_SIGINT; -static int volatile signal_received; -static int sigs_trapped; - -static RETSIGTYPE -catchsig (s) - int s; -{ -#if ! HAVE_SIGACTION - signal (s, SIG_IGN); -#endif - if (! (s == SIGINT && ignore_SIGINT)) - signal_received = s; -} - -static void -trapsigs () -{ - int i; - -#if HAVE_SIGACTION - struct sigaction catchaction; - bzero (&catchaction, sizeof (catchaction)); - catchaction.sa_handler = catchsig; -#ifdef SA_INTERRUPT - /* Non-Posix BSD-style systems like SunOS 4.1.x need this - so that `read' calls are interrupted properly. */ - catchaction.sa_flags = SA_INTERRUPT; -#endif - sigemptyset (&catchaction.sa_mask); - for (i = 0; i < NUM_SIGS; i++) - sigaddset (&catchaction.sa_mask, sigs[i]); - for (i = 0; i < NUM_SIGS; i++) - { - sigaction (sigs[i], 0, &initial_action[i]); - if (initial_handler (i) != SIG_IGN - && sigaction (sigs[i], &catchaction, 0) != 0) - fatal ("signal error"); - } -#else /* ! HAVE_SIGACTION */ - for (i = 0; i < NUM_SIGS; i++) - { - initial_action[i] = signal (sigs[i], SIG_IGN); - if (initial_handler (i) != SIG_IGN - && signal (sigs[i], catchsig) != SIG_IGN) - fatal ("signal error"); - } -#endif /* ! HAVE_SIGACTION */ - -#if !defined(SIGCHLD) && defined(SIGCLD) -#define SIGCHLD SIGCLD -#endif -#ifdef SIGCHLD - /* System V fork+wait does not work if SIGCHLD is ignored. */ - signal (SIGCHLD, SIG_DFL); -#endif - - sigs_trapped = 1; -} - -/* Untrap signal S, or all trapped signals if S is zero. */ -static void -untrapsig (s) - int s; -{ - int i; - - if (sigs_trapped) - for (i = 0; i < NUM_SIGS; i++) - if ((!s || sigs[i] == s) && initial_handler (i) != SIG_IGN) -#if HAVE_SIGACTION - sigaction (sigs[i], &initial_action[i], 0); -#else - signal (sigs[i], initial_action[i]); -#endif -} - -/* Exit if a signal has been received. */ -static void -checksigs () -{ - int s = signal_received; - if (s) - { - cleanup (); - - /* Yield an exit status indicating that a signal was received. */ - untrapsig (s); - kill (getpid (), s); - - /* That didn't work, so exit with error status. */ - exit (2); - } -} - - - -static void -give_help () -{ - fprintf (stderr,"l:\tuse the left version\n"); - fprintf (stderr,"r:\tuse the right version\n"); - fprintf (stderr,"e l:\tedit then use the left version\n"); - fprintf (stderr,"e r:\tedit then use the right version\n"); - fprintf (stderr,"e b:\tedit then use the left and right versions concatenated\n"); - fprintf (stderr,"e:\tedit a new version\n"); - fprintf (stderr,"s:\tsilently include common lines\n"); - fprintf (stderr,"v:\tverbosely include common lines\n"); - fprintf (stderr,"q:\tquit\n"); -} - -static int -skip_white () -{ - int c; - for (;;) - { - c = getchar (); - if (!ISSPACE (c) || c == '\n') - break; - checksigs (); - } - if (ferror (stdin)) - perror_fatal ("input error"); - return c; -} - -static void -flush_line () -{ - int c; - while ((c = getchar ()) != '\n' && c != EOF) - ; - if (ferror (stdin)) - perror_fatal ("input error"); -} - - -/* interpret an edit command */ -static int -edit (left, lenl, right, lenr, outfile) - struct line_filter *left; - int lenl; - struct line_filter *right; - int lenr; - FILE *outfile; -{ - for (;;) - { - int cmd0, cmd1; - int gotcmd = 0; - - cmd1 = 0; /* Pacify `gcc -W'. */ - - while (!gotcmd) - { - if (putchar ('%') != '%') - perror_fatal ("output error"); - ck_fflush (stdout); - - cmd0 = skip_white (); - switch (cmd0) - { - case 'l': case 'r': case 's': case 'v': case 'q': - if (skip_white () != '\n') - { - give_help (); - flush_line (); - continue; - } - gotcmd = 1; - break; - - case 'e': - cmd1 = skip_white (); - switch (cmd1) - { - case 'l': case 'r': case 'b': - if (skip_white () != '\n') - { - give_help (); - flush_line (); - continue; - } - gotcmd = 1; - break; - case '\n': - gotcmd = 1; - break; - default: - give_help (); - flush_line (); - continue; - } - break; - case EOF: - if (feof (stdin)) - { - gotcmd = 1; - cmd0 = 'q'; - break; - } - /* falls through */ - default: - flush_line (); - /* falls through */ - case '\n': - give_help (); - continue; - } - } - - switch (cmd0) - { - case 'l': - lf_copy (left, lenl, outfile); - lf_skip (right, lenr); - return 1; - case 'r': - lf_copy (right, lenr, outfile); - lf_skip (left, lenl); - return 1; - case 's': - suppress_common_flag = 1; - break; - case 'v': - suppress_common_flag = 0; - break; - case 'q': - return 0; - case 'e': - if (! tmpname && ! (tmpname = private_tempnam ())) - perror_fatal ("temporary file name"); - - tmpmade = 1; - - { - FILE *tmp = ck_fopen (tmpname, "w+"); - - if (cmd1 == 'l' || cmd1 == 'b') - lf_copy (left, lenl, tmp); - else - lf_skip (left, lenl); - - if (cmd1 == 'r' || cmd1 == 'b') - lf_copy (right, lenr, tmp); - else - lf_skip (right, lenr); - - ck_fflush (tmp); - - { - int wstatus; -#if ! HAVE_FORK - char *command = xmalloc (strlen (edbin) + strlen (tmpname) + 2); - sprintf (command, "%s %s", edbin, tmpname); - wstatus = system (command); - free (command); -#else /* HAVE_FORK */ - pid_t pid; - - ignore_SIGINT = 1; - checksigs (); - - pid = vfork (); - if (pid == 0) - { - char const *argv[3]; - int i = 0; - - argv[i++] = edbin; - argv[i++] = tmpname; - argv[i++] = 0; - - execvp (edbin, (char **) argv); - write (STDERR_FILENO, edbin, strlen (edbin)); - write (STDERR_FILENO, ": not found\n", 12); - _exit (1); - } - - if (pid < 0) - perror_fatal ("fork failed"); - - while (waitpid (pid, &wstatus, 0) < 0) - if (errno == EINTR) - checksigs (); - else - perror_fatal ("wait failed"); - - ignore_SIGINT = 0; -#endif /* HAVE_FORK */ - - if (wstatus != 0) - fatal ("Subsidiary editor failed"); - } - - if (fseek (tmp, 0L, SEEK_SET) != 0) - perror_fatal ("fseek"); - { - /* SDIFF_BUFSIZE is too big for a local var - in some compilers, so we allocate it dynamically. */ - char *buf = xmalloc (SDIFF_BUFSIZE); - size_t size; - - while ((size = ck_fread (buf, SDIFF_BUFSIZE, tmp)) != 0) - { - checksigs (); - ck_fwrite (buf, size, outfile); - } - ck_fclose (tmp); - - free (buf); - } - return 1; - } - default: - give_help (); - break; - } - } -} - - - -/* Alternately reveal bursts of diff output and handle user commands. */ -static int -interact (diff, left, right, outfile) - struct line_filter *diff; - struct line_filter *left; - struct line_filter *right; - FILE *outfile; -{ - for (;;) - { - char diff_help[256]; - int snarfed = lf_snarf (diff, diff_help, sizeof (diff_help)); - - if (snarfed <= 0) - return snarfed; - - checksigs (); - - switch (diff_help[0]) - { - case ' ': - puts (diff_help + 1); - break; - case 'i': - { - int lenl = atoi (diff_help + 1), lenr, lenmax; - char *p = strchr (diff_help, ','); - - if (!p) - fatal (diff_help); - lenr = atoi (p + 1); - lenmax = max (lenl, lenr); - - if (suppress_common_flag) - lf_skip (diff, lenmax); - else - lf_copy (diff, lenmax, stdout); - - lf_copy (left, lenl, outfile); - lf_skip (right, lenr); - break; - } - case 'c': - { - int lenl = atoi (diff_help + 1), lenr; - char *p = strchr (diff_help, ','); - - if (!p) - fatal (diff_help); - lenr = atoi (p + 1); - lf_copy (diff, max (lenl, lenr), stdout); - if (! edit (left, lenl, right, lenr, outfile)) - return 0; - break; - } - default: - fatal (diff_help); - break; - } - } -} - - - -/* temporary lossage: this is torn from gnu libc */ -/* Return nonzero if DIR is an existing directory. */ -static int -diraccess (dir) - char const *dir; -{ - struct stat buf; - return stat (dir, &buf) == 0 && S_ISDIR (buf.st_mode); -} - -#if ! HAVE_TMPNAM - -/* Return zero if we know that FILE does not exist. */ -static int -exists (file) - char const *file; -{ - struct stat buf; - return stat (file, &buf) == 0 || errno != ENOENT; -} - -/* These are the characters used in temporary filenames. */ -static char const letters[] = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - -/* Generate a temporary filename and return it (in a newly allocated buffer). - Use the prefix "dif" as in tempnam. - This goes through a cyclic pattern of all possible - filenames consisting of five decimal digits of the current pid and three - of the characters in `letters'. Each potential filename is - tested for an already-existing file of the same name, and no name of an - existing file will be returned. When the cycle reaches its end - return 0. */ -static char * -private_tempnam () -{ - char const *dir = getenv (TMPDIR_ENV); - static char const tmpdir[] = PVT_tmpdir; - size_t index; - char *buf; - pid_t pid = getpid (); - size_t dlen; - - if (!dir) - dir = tmpdir; - - dlen = strlen (dir); - - /* Remove trailing slashes from the directory name. */ - while (dlen && dir[dlen - 1] == '/') - --dlen; - - buf = xmalloc (dlen + 1 + 3 + 5 + 1 + 3 + 1); - - sprintf (buf, "%.*s/.", (int) dlen, dir); - if (diraccess (buf)) - { - for (index = 0; - index < ((sizeof (letters) - 1) * (sizeof (letters) - 1) - * (sizeof (letters) - 1)); - ++index) - { - /* Construct a file name and see if it already exists. - - We use a single counter in INDEX to cycle each of three - character positions through each of 62 possible letters. */ - - sprintf (buf, "%.*s/dif%.5lu.%c%c%c", (int) dlen, dir, - (unsigned long) pid % 100000, - letters[index % (sizeof (letters) - 1)], - letters[(index / (sizeof (letters) - 1)) - % (sizeof (letters) - 1)], - letters[index / ((sizeof (letters) - 1) * - (sizeof (letters) - 1))]); - - if (!exists (buf)) - return buf; - } - errno = EEXIST; - } - - /* Don't free buf; `free' might change errno. We'll exit soon anyway. */ - return 0; -} - -#endif /* ! HAVE_TMPNAM */ diff --git a/gnu/usr.bin/diff/side.c b/gnu/usr.bin/diff/side.c deleted file mode 100644 index a150b5e705fc..000000000000 --- a/gnu/usr.bin/diff/side.c +++ /dev/null @@ -1,284 +0,0 @@ -/* sdiff-format output routines for GNU DIFF. - Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. - -This file is part of GNU DIFF. - -GNU DIFF is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY. No author or distributor -accepts responsibility to anyone for the consequences of using it -or for whether it serves any particular purpose or works at all, -unless he says so in writing. Refer to the GNU DIFF General Public -License for full details. - -Everyone is granted permission to copy, modify and redistribute -GNU DIFF, but only under the conditions described in the -GNU DIFF General Public License. A copy of this license is -supposed to have been given to you along with GNU DIFF so you -can know your rights and responsibilities. It should be in a -file named COPYING. Among other things, the copyright notice -and this notice must be preserved on all copies. */ - - -#include "diff.h" - -static unsigned print_half_line PARAMS((char const * const *, unsigned, unsigned)); -static unsigned tab_from_to PARAMS((unsigned, unsigned)); -static void print_1sdiff_line PARAMS((char const * const *, int, char const * const *)); -static void print_sdiff_common_lines PARAMS((int, int)); -static void print_sdiff_hunk PARAMS((struct change *)); - -/* Next line number to be printed in the two input files. */ -static int next0, next1; - -/* Print the edit-script SCRIPT as a sdiff style output. */ - -void -print_sdiff_script (script) - struct change *script; -{ - begin_output (); - - next0 = next1 = - files[0].prefix_lines; - print_script (script, find_change, print_sdiff_hunk); - - print_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines); -} - -/* Tab from column FROM to column TO, where FROM <= TO. Yield TO. */ - -static unsigned -tab_from_to (from, to) - unsigned from, to; -{ - FILE *out = outfile; - unsigned tab; - - if (! tab_expand_flag) - for (tab = from + TAB_WIDTH - from % TAB_WIDTH; tab <= to; tab += TAB_WIDTH) - { - putc ('\t', out); - from = tab; - } - while (from++ < to) - putc (' ', out); - return to; -} - -/* - * Print the text for half an sdiff line. This means truncate to width - * observing tabs, and trim a trailing newline. Returns the last column - * written (not the number of chars). - */ -static unsigned -print_half_line (line, indent, out_bound) - char const * const *line; - unsigned indent, out_bound; -{ - FILE *out = outfile; - register unsigned in_position = 0, out_position = 0; - register char const - *text_pointer = line[0], - *text_limit = line[1]; - - while (text_pointer < text_limit) - { - register unsigned char c = *text_pointer++; - - switch (c) - { - case '\t': - { - unsigned spaces = TAB_WIDTH - in_position % TAB_WIDTH; - if (in_position == out_position) - { - unsigned tabstop = out_position + spaces; - if (tab_expand_flag) - { - if (out_bound < tabstop) - tabstop = out_bound; - for (; out_position < tabstop; out_position++) - putc (' ', out); - } - else - if (tabstop < out_bound) - { - out_position = tabstop; - putc (c, out); - } - } - in_position += spaces; - } - break; - - case '\r': - { - putc (c, out); - tab_from_to (0, indent); - in_position = out_position = 0; - } - break; - - case '\b': - if (in_position != 0 && --in_position < out_bound) - if (out_position <= in_position) - /* Add spaces to make up for suppressed tab past out_bound. */ - for (; out_position < in_position; out_position++) - putc (' ', out); - else - { - out_position = in_position; - putc (c, out); - } - break; - - case '\f': - case '\v': - control_char: - if (in_position < out_bound) - putc (c, out); - break; - - default: - if (! ISPRINT (c)) - goto control_char; - /* falls through */ - case ' ': - if (in_position++ < out_bound) - { - out_position = in_position; - putc (c, out); - } - break; - - case '\n': - return out_position; - } - } - - return out_position; -} - -/* - * Print side by side lines with a separator in the middle. - * 0 parameters are taken to indicate white space text. - * Blank lines that can easily be caught are reduced to a single newline. - */ - -static void -print_1sdiff_line (left, sep, right) - char const * const *left; - int sep; - char const * const *right; -{ - FILE *out = outfile; - unsigned hw = sdiff_half_width, c2o = sdiff_column2_offset; - unsigned col = 0; - int put_newline = 0; - - if (left) - { - if (left[1][-1] == '\n') - put_newline = 1; - col = print_half_line (left, 0, hw); - } - - if (sep != ' ') - { - col = tab_from_to (col, (hw + c2o - 1) / 2) + 1; - if (sep == '|' && put_newline != (right[1][-1] == '\n')) - sep = put_newline ? '/' : '\\'; - putc (sep, out); - } - - if (right) - { - if (right[1][-1] == '\n') - put_newline = 1; - if (**right != '\n') - { - col = tab_from_to (col, c2o); - print_half_line (right, col, hw); - } - } - - if (put_newline) - putc ('\n', out); -} - -/* Print lines common to both files in side-by-side format. */ -static void -print_sdiff_common_lines (limit0, limit1) - int limit0, limit1; -{ - int i0 = next0, i1 = next1; - - if (! sdiff_skip_common_lines && (i0 != limit0 || i1 != limit1)) - { - if (sdiff_help_sdiff) - fprintf (outfile, "i%d,%d\n", limit0 - i0, limit1 - i1); - - if (! sdiff_left_only) - { - while (i0 != limit0 && i1 != limit1) - print_1sdiff_line (&files[0].linbuf[i0++], ' ', &files[1].linbuf[i1++]); - while (i1 != limit1) - print_1sdiff_line (0, ')', &files[1].linbuf[i1++]); - } - while (i0 != limit0) - print_1sdiff_line (&files[0].linbuf[i0++], '(', 0); - } - - next0 = limit0; - next1 = limit1; -} - -/* Print a hunk of an sdiff diff. - This is a contiguous portion of a complete edit script, - describing changes in consecutive lines. */ - -static void -print_sdiff_hunk (hunk) - struct change *hunk; -{ - int first0, last0, first1, last1, deletes, inserts; - register int i, j; - - /* Determine range of line numbers involved in each file. */ - analyze_hunk (hunk, &first0, &last0, &first1, &last1, &deletes, &inserts); - if (!deletes && !inserts) - return; - - /* Print out lines up to this change. */ - print_sdiff_common_lines (first0, first1); - - if (sdiff_help_sdiff) - fprintf (outfile, "c%d,%d\n", last0 - first0 + 1, last1 - first1 + 1); - - /* Print ``xxx | xxx '' lines */ - if (inserts && deletes) - { - for (i = first0, j = first1; i <= last0 && j <= last1; ++i, ++j) - print_1sdiff_line (&files[0].linbuf[i], '|', &files[1].linbuf[j]); - deletes = i <= last0; - inserts = j <= last1; - next0 = first0 = i; - next1 = first1 = j; - } - - - /* Print `` > xxx '' lines */ - if (inserts) - { - for (j = first1; j <= last1; ++j) - print_1sdiff_line (0, '>', &files[1].linbuf[j]); - next1 = j; - } - - /* Print ``xxx < '' lines */ - if (deletes) - { - for (i = first0; i <= last0; ++i) - print_1sdiff_line (&files[0].linbuf[i], '<', 0); - next0 = i; - } -} diff --git a/gnu/usr.bin/diff/system.h b/gnu/usr.bin/diff/system.h deleted file mode 100644 index d60af60005f5..000000000000 --- a/gnu/usr.bin/diff/system.h +++ /dev/null @@ -1,267 +0,0 @@ -/* System dependent declarations. - Copyright (C) 1988, 1989, 1992, 1993, 1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* We must define `volatile' and `const' first (the latter inside config.h), - so that they're used consistently in all system includes. */ -#if !__STDC__ -#ifndef volatile -#define volatile -#endif -#endif -#include - -#include -#include - -#if __STDC__ -#define PARAMS(args) args -#define VOID void -#else -#define PARAMS(args) () -#define VOID char -#endif - -#if STAT_MACROS_BROKEN -#undef S_ISBLK -#undef S_ISCHR -#undef S_ISDIR -#undef S_ISFIFO -#undef S_ISREG -#undef S_ISSOCK -#endif -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#endif -#ifndef S_ISREG -#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) -#endif -#if !defined(S_ISBLK) && defined(S_IFBLK) -#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) -#endif -#if !defined(S_ISCHR) && defined(S_IFCHR) -#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) -#endif -#if !defined(S_ISFIFO) && defined(S_IFFIFO) -#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) -#endif -#if !defined(S_ISSOCK) && defined(S_IFSOCK) -#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) -#endif - -#if HAVE_UNISTD_H -#include -#endif - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif - -#if HAVE_TIME_H -#include -#else -#include -#endif - -#if HAVE_FCNTL_H -#include -#else -#if HAVE_SYS_FILE_H -#include -#endif -#endif - -#if !HAVE_DUP2 -#define dup2(f,t) (close (t), fcntl (f,F_DUPFD,t)) -#endif - -#ifndef O_RDONLY -#define O_RDONLY 0 -#endif - -#if HAVE_SYS_WAIT_H -#include -#endif -#ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned) (stat_val) >> 8) -#endif -#ifndef WIFEXITED -#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -#endif - -#ifndef STAT_BLOCKSIZE -#if HAVE_ST_BLKSIZE -#define STAT_BLOCKSIZE(s) (s).st_blksize -#else -#define STAT_BLOCKSIZE(s) (8 * 1024) -#endif -#endif - -#if HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) ((dirent)->d_namlen) -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif - -#if HAVE_VFORK_H -#include -#endif - -#if HAVE_STDLIB_H -#include -#else -VOID *malloc (); -VOID *realloc (); -#endif -#ifndef getenv -char *getenv (); -#endif - -#if HAVE_LIMITS_H -#include -#endif -#ifndef INT_MAX -#define INT_MAX 2147483647 -#endif -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif - -#if STDC_HEADERS || HAVE_STRING_H -# include -# ifndef bzero -# define bzero(s, n) memset (s, 0, n) -# endif -#else -# if !HAVE_STRCHR -# define strchr index -# define strrchr rindex -# endif -char *strchr (), *strrchr (); -# if !HAVE_MEMCHR -# define memcmp(s1, s2, n) bcmp (s1, s2, n) -# define memcpy(d, s, n) bcopy (s, d, n) -void *memchr (); -# endif -#endif - -#include -/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given - as an argument to macros like `isspace'. */ -#if STDC_HEADERS -#define CTYPE_DOMAIN(c) 1 -#else -#define CTYPE_DOMAIN(c) ((unsigned) (c) <= 0177) -#endif -#ifndef ISPRINT -#define ISPRINT(c) (CTYPE_DOMAIN (c) && isprint (c)) -#endif -#ifndef ISSPACE -#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c)) -#endif -#ifndef ISUPPER -#define ISUPPER(c) (CTYPE_DOMAIN (c) && isupper (c)) -#endif - -#ifndef ISDIGIT -#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) -#endif - -#include -#if !STDC_HEADERS -extern int errno; -#endif - -#ifdef min -#undef min -#endif -#ifdef max -#undef max -#endif -#define min(a,b) ((a) <= (b) ? (a) : (b)) -#define max(a,b) ((a) >= (b) ? (a) : (b)) - -/* This section contains Posix-compliant defaults for macros - that are meant to be overridden by hand in config.h as needed. */ - -#ifndef filename_cmp -#define filename_cmp(a, b) strcmp (a, b) -#endif - -#ifndef filename_lastdirchar -#define filename_lastdirchar(filename) strrchr (filename, '/') -#endif - -#ifndef HAVE_FORK -#define HAVE_FORK 1 -#endif - -#ifndef HAVE_SETMODE -#define HAVE_SETMODE 0 -#endif - -#ifndef initialize_main -#define initialize_main(argcp, argvp) -#endif - -/* Do struct stat *S, *T describe the same file? Answer -1 if unknown. */ -#ifndef same_file -#define same_file(s,t) ((s)->st_ino==(t)->st_ino && (s)->st_dev==(t)->st_dev) -#endif - -/* Place into Q a quoted version of A suitable for `popen' or `system', - incrementing Q and junking A. - Do not increment Q by more than 4 * strlen (A) + 2. */ -#ifndef SYSTEM_QUOTE_ARG -#define SYSTEM_QUOTE_ARG(q, a) \ - { \ - *(q)++ = '\''; \ - for (; *(a); *(q)++ = *(a)++) \ - if (*(a) == '\'') \ - { \ - *(q)++ = '\''; \ - *(q)++ = '\\'; \ - *(q)++ = '\''; \ - } \ - *(q)++ = '\''; \ - } -#endif diff --git a/gnu/usr.bin/diff/util.c b/gnu/usr.bin/diff/util.c deleted file mode 100644 index 1765b1f4f4f9..000000000000 --- a/gnu/usr.bin/diff/util.c +++ /dev/null @@ -1,754 +0,0 @@ -/* Support routines for GNU DIFF. - Copyright (C) 1988, 1989, 1992, 1993, 1994 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 GNU DIFF; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "diff.h" - -#ifndef PR_PROGRAM -#define PR_PROGRAM "/bin/pr" -#endif - -/* 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 const *format; - char const *arg1; - char const *arg2; - char const *arg3; - char const *arg4; -}; - -/* 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. - TEXT should normally be the file name. */ - -void -perror_with_name (text) - char const *text; -{ - int e = errno; - fprintf (stderr, "%s: ", program_name); - errno = e; - perror (text); -} - -/* Use when a system call returns non-zero status and that is fatal. */ - -void -pfatal_with_name (text) - char const *text; -{ - int e = errno; - print_message_queue (); - fprintf (stderr, "%s: ", program_name); - errno = e; - perror (text); - exit (2); -} - -/* Print an error message from the format-string FORMAT - with args ARG1 and ARG2. */ - -void -error (format, arg, arg1) - char const *format, *arg, *arg1; -{ - fprintf (stderr, "%s: ", program_name); - fprintf (stderr, format, arg, arg1); - fprintf (stderr, "\n"); -} - -/* Print an error message containing the string TEXT, then exit. */ - -void -fatal (m) - char const *m; -{ - print_message_queue (); - error ("%s", m, 0); - exit (2); -} - -/* Like printf, except if -l in effect then save the message and print later. - This is used for things like "binary files differ" and "Only in ...". */ - -void -message (format, arg1, arg2) - char const *format, *arg1, *arg2; -{ - message5 (format, arg1, arg2, 0, 0); -} - -void -message5 (format, arg1, arg2, arg3, arg4) - char const *format, *arg1, *arg2, *arg3, *arg4; -{ - if (paginate_flag) - { - struct msg *new = (struct msg *) xmalloc (sizeof (struct msg)); - new->format = format; - new->arg1 = concat (arg1, "", ""); - new->arg2 = concat (arg2, "", ""); - new->arg3 = arg3 ? concat (arg3, "", "") : 0; - new->arg4 = arg4 ? concat (arg4, "", "") : 0; - new->next = 0; - *msg_chain_end = new; - msg_chain_end = &new->next; - } - else - { - if (sdiff_help_sdiff) - putchar (' '); - printf (format, arg1, arg2, arg3, arg4); - } -} - -/* Output all the messages that were saved up by calls to `message'. */ - -void -print_message_queue () -{ - struct msg *m; - - for (m = msg_chain; m; m = m->next) - printf (m->format, m->arg1, m->arg2, m->arg3, m->arg4); -} - -/* 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 int current_depth; - -void -setup_output (name0, name1, depth) - char const *name0, *name1; - int depth; -{ - current_name0 = name0; - current_name1 = name1; - current_depth = depth; - outfile = 0; -} - -#if HAVE_FORK -static pid_t pr_pid; -#endif - -void -begin_output () -{ - 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.2 section 4.17.6.1.1 specifies this format. But there is a - bug in the first printing (IEEE Std 1003.2-1992 p 251 l 3304): - it says that we must print only the last component of the pathnames. - This requirement is silly and does not match historical practice. */ - sprintf (name, "diff%s %s %s", switch_string, current_name0, current_name1); - - if (paginate_flag) - { - /* Make OUTFILE a pipe to a subsidiary `pr'. */ - -#if HAVE_FORK - int pipes[2]; - - if (pipe (pipes) != 0) - pfatal_with_name ("pipe"); - - fflush (stdout); - - pr_pid = vfork (); - if (pr_pid < 0) - pfatal_with_name ("vfork"); - - 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, "-F", "-h", name, 0); - pfatal_with_name (PR_PROGRAM); - } - else - { - close (pipes[0]); - outfile = fdopen (pipes[1], "w"); - if (!outfile) - pfatal_with_name ("fdopen"); - } -#else /* ! HAVE_FORK */ - char *command = xmalloc (4 * strlen (name) + strlen (PR_PROGRAM) + 10); - char *p; - char const *a = name; - sprintf (command, "%s -f -h ", PR_PROGRAM); - p = command + strlen (command); - SYSTEM_QUOTE_ARG (p, a); - *p = 0; - outfile = popen (command, "w"); - if (!outfile) - pfatal_with_name (command); - free (command); -#endif /* ! HAVE_FORK */ - } - 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 (current_depth > 0) - 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 () -{ - if (outfile != 0 && outfile != stdout) - { - int wstatus; - if (ferror (outfile)) - fatal ("write error"); -#if ! HAVE_FORK - wstatus = pclose (outfile); -#else /* HAVE_FORK */ - if (fclose (outfile) != 0) - pfatal_with_name ("write error"); - if (waitpid (pr_pid, &wstatus, 0) < 0) - pfatal_with_name ("waitpid"); -#endif /* HAVE_FORK */ - if (wstatus != 0) - fatal ("subsidiary pr failed"); - } - - 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. */ - -int -line_cmp (s1, s2) - char const *s1, *s2; -{ - register unsigned char const *t1 = (unsigned char const *) s1; - register unsigned char const *t2 = (unsigned char const *) s2; - - 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) - { - /* Ignore horizontal white space if -b or -w is specified. */ - - if (ignore_all_space_flag) - { - /* For -w, just skip past any white space. */ - while (ISSPACE (c1) && c1 != '\n') c1 = *t1++; - while (ISSPACE (c2) && c2 != '\n') c2 = *t2++; - } - else if (ignore_space_change_flag) - { - /* 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; - } - } - } - - /* Lowercase all letters if -i is specified. */ - - if (ignore_case_flag) - { - if (ISUPPER (c1)) - c1 = tolower (c1); - if (ISUPPER (c2)) - c2 = tolower (c2); - } - - if (c1 != c2) - break; - } - if (c1 == '\n') - return 0; - } - - 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 (start) - struct change *start; -{ - return start; -} - -struct change * -find_reverse_change (start) - 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 (script, hunkfun, printfun) - struct change *script; - struct change * (*hunkfun) PARAMS((struct change *)); - void (*printfun) PARAMS((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 (line_flag, line) - char const *line_flag; - char const * const *line; -{ - char const *text = 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 = tab_align_flag ? "%s\t" : "%s "; - fprintf (out, flag_format, line_flag); - } - - output_1_line (text, limit, flag_format, line_flag); - - if ((!line_flag || line_flag[0]) && limit[-1] != '\n') - fprintf (out, "\n\\ No newline at end of file\n"); -} - -/* Output a line from TEXT up to LIMIT. Without -t, output verbatim. - 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 (text, limit, flag_format, line_flag) - char const *text, *limit, *flag_format, *line_flag; -{ - if (!tab_expand_flag) - fwrite (text, sizeof (char), limit - text, outfile); - else - { - register FILE *out = outfile; - register unsigned char c; - register char const *t = text; - register unsigned column = 0; - - while (t < limit) - switch ((c = *t++)) - { - case '\t': - { - unsigned 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; - } - } -} - -int -change_letter (inserts, deletes) - int inserts, deletes; -{ - if (!inserts) - return 'd'; - else if (!deletes) - return 'a'; - else - return '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 LNUM. 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. */ - -int -translate_line_number (file, lnum) - struct file_data const *file; - int lnum; -{ - return lnum + file->prefix_lines + 1; -} - -void -translate_range (file, a, b, aptr, bptr) - struct file_data const *file; - int a, b; - int *aptr, *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 (sepchar, file, a, b) - int sepchar; - struct file_data *file; - int a, b; -{ - int 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, "%d%c%d", trans_a, sepchar, trans_b); - else - fprintf (outfile, "%d", 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. - - Also set *DELETES nonzero if any lines of file 0 are deleted - and set *INSERTS nonzero if any lines of file 1 are inserted. - If only ignorable lines are inserted or deleted, both are - set to 0. */ - -void -analyze_hunk (hunk, first0, last0, first1, last1, deletes, inserts) - struct change *hunk; - int *first0, *last0, *first1, *last1; - int *deletes, *inserts; -{ - int l0, l1, show_from, show_to; - int i; - int trivial = ignore_blank_lines_flag || ignore_regexp_list; - struct change *next; - - 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++) - if (!ignore_blank_lines_flag || files[0].linbuf[i][0] != '\n') - { - struct regexp_list *r; - char const *line = files[0].linbuf[i]; - int len = files[0].linbuf[i + 1] - line; - - for (r = ignore_regexp_list; r; r = r->next) - if (0 <= re_search (&r->buf, line, len, 0, len, 0)) - break; /* Found a match. Ignore this line. */ - /* If we got all the way through the regexp list without - finding a match, then it's nontrivial. */ - if (!r) - trivial = 0; - } - - for (i = next->line1; i <= l1 && trivial; i++) - if (!ignore_blank_lines_flag || files[1].linbuf[i][0] != '\n') - { - struct regexp_list *r; - char const *line = files[1].linbuf[i]; - int len = files[1].linbuf[i + 1] - line; - - for (r = ignore_regexp_list; r; r = r->next) - if (0 <= re_search (&r->buf, line, len, 0, len, 0)) - break; /* Found a match. Ignore this line. */ - /* If we got all the way through the regexp list without - finding a match, then it's nontrivial. */ - if (!r) - 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) - show_from = show_to = 0; - - *deletes = show_from; - *inserts = show_to; -} - -/* malloc a block of memory, with fatal error message if we can't do it. */ - -VOID * -xmalloc (size) - size_t size; -{ - register VOID *value; - - if (size == 0) - size = 1; - - value = (VOID *) malloc (size); - - if (!value) - fatal ("memory exhausted"); - return value; -} - -/* realloc a block of memory, with fatal error message if we can't do it. */ - -VOID * -xrealloc (old, size) - VOID *old; - size_t size; -{ - register VOID *value; - - if (size == 0) - size = 1; - - value = (VOID *) realloc (old, size); - - if (!value) - fatal ("memory exhausted"); - return value; -} - -/* Concatenate three strings, returning a newly malloc'd string. */ - -char * -concat (s1, s2, s3) - char const *s1, *s2, *s3; -{ - size_t len = strlen (s1) + strlen (s2) + strlen (s3); - char *new = xmalloc (len + 1); - sprintf (new, "%s%s%s", s1, s2, s3); - return new; -} - -/* Yield the newly malloc'd pathname - of the file in DIR whose filename is FILE. */ - -char * -dir_file_pathname (dir, file) - char const *dir, *file; -{ - char const *p = filename_lastdirchar (dir); - return concat (dir, "/" + (p && !p[1]), file); -} - -void -debug_script (sp) - struct change *sp; -{ - fflush (stdout); - for (; sp; sp = sp->link) - fprintf (stderr, "%3d %3d delete %d insert %d\n", - sp->line0, sp->line1, sp->deleted, sp->inserted); - fflush (stderr); -} diff --git a/gnu/usr.bin/diff/version.c b/gnu/usr.bin/diff/version.c deleted file mode 100644 index 02993976351b..000000000000 --- a/gnu/usr.bin/diff/version.c +++ /dev/null @@ -1,5 +0,0 @@ -/* Version number of GNU diff. */ - -#include - -char const version_string[] = "2.7"; diff --git a/gnu/usr.bin/diff3/Makefile b/gnu/usr.bin/diff3/Makefile index cfac721af698..4b9dd6797f74 100644 --- a/gnu/usr.bin/diff3/Makefile +++ b/gnu/usr.bin/diff3/Makefile @@ -1,12 +1,14 @@ -# $NetBSD: Makefile,v 1.9 1997/10/25 10:10:32 lukem Exp $ +# $NetBSD: Makefile,v 1.10 1999/02/12 12:45:13 tv Exp $ PROG= diff3 SRCS= diff3.c getopt.c getopt1.c version.c -CPPFLAGS+= -I$(.CURDIR)/../diff \ +CPPFLAGS+= -I${.CURDIR}/../diff -I${DIST}/diffutils \ -DHAVE_CONFIG_H -DDIFF_PROGRAM=\"/usr/bin/diff\" LDADD+= -lgnumalloc DPADD+= ${LIBGNUMALLOC} +DIST= ${.CURDIR}/../../dist +.PATH: ${.CURDIR}/../diff ${DIST}/diffutils + .include -.PATH: $(.CURDIR)/../diff diff --git a/gnu/usr.bin/sdiff/Makefile b/gnu/usr.bin/sdiff/Makefile index 08b6393d04db..667280785fbc 100644 --- a/gnu/usr.bin/sdiff/Makefile +++ b/gnu/usr.bin/sdiff/Makefile @@ -1,12 +1,14 @@ -# $NetBSD: Makefile,v 1.8 1997/10/25 10:12:54 lukem Exp $ +# $NetBSD: Makefile,v 1.9 1999/02/12 12:45:13 tv Exp $ PROG= sdiff SRCS= sdiff.c getopt.c getopt1.c version.c -CPPFLAGS+= -I$(.CURDIR)/../diff \ +CPPFLAGS+= -I${.CURDIR}/../diff -I${DIST}/diffutils \ -DHAVE_CONFIG_H -DDIFF_PROGRAM=\"/usr/bin/diff\" LDADD+= -lgnumalloc DPADD+= ${LIBGNUMALLOC} +DIST= ${.CURDIR}/../../dist +.PATH: ${.CURDIR}/../diff ${DIST}/diffutils + .include -.PATH: $(.CURDIR)/../diff