diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2024-03-11 13:44:36 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2024-03-11 13:48:08 +0000 |
commit | 59c8e88e72633afbc47a4ace0d2170d00d51f7dc (patch) | |
tree | 95071a3c8ddfaaa961195b99ea547fbb43145388 /contrib/libdiff/diff | |
parent | f6d489f402c320f1a6eaa473491a0b8c3878113e (diff) | |
parent | 9eb461aa4b61ab47855b2cee9e5b626a76888b5e (diff) |
Diffstat (limited to 'contrib/libdiff/diff')
-rw-r--r-- | contrib/libdiff/diff/GNUmakefile | 19 | ||||
-rw-r--r-- | contrib/libdiff/diff/Makefile | 41 | ||||
-rw-r--r-- | contrib/libdiff/diff/diff.c | 280 |
3 files changed, 340 insertions, 0 deletions
diff --git a/contrib/libdiff/diff/GNUmakefile b/contrib/libdiff/diff/GNUmakefile new file mode 100644 index 000000000000..63d0b8795665 --- /dev/null +++ b/contrib/libdiff/diff/GNUmakefile @@ -0,0 +1,19 @@ +CFLAGS = -fsanitize=address -fsanitize=undefined -g -O3 +CFLAGS += -Wstrict-prototypes -Wunused-variable -Wuninitialized + +SRCS= diff.c +LIB= ../lib/libdiff.a + +# Compat sources +CFLAGS+= -I$(CURDIR)/../compat/include + +diff: $(SRCS) $(LIB) + gcc $(CFLAGS) -I../include -o $@ $^ + +../lib/libdiff.a: ../lib/*.[hc] ../include/*.h + $(MAKE) -C ../lib + +.PHONY: clean +clean: + rm diff + $(MAKE) -C ../lib clean diff --git a/contrib/libdiff/diff/Makefile b/contrib/libdiff/diff/Makefile new file mode 100644 index 000000000000..4a7f3a9755f5 --- /dev/null +++ b/contrib/libdiff/diff/Makefile @@ -0,0 +1,41 @@ +.PATH:${.CURDIR}/../lib + +.include "../diff-version.mk" + +PROG= diff +SRCS= \ + diff.c \ + diff_atomize_text.c \ + diff_main.c \ + diff_myers.c \ + diff_patience.c \ + diff_output.c \ + diff_output_plain.c \ + diff_output_unidiff.c \ + diff_output_edscript.c \ + ${END} +MAN = ${PROG}.1 + +CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib +#CPPFLAGS += -DDIFF_NO_MMAP + +.if defined(PROFILE) +CFLAGS = -O0 -pg -g +LDFLAGS = -pg -lc_p -lutil_p -lz_p -static +.else +LDFLAGS = -lutil -lz +.endif + +.if ${DIFF_RELEASE} != "Yes" +NOMAN = Yes +.endif + +realinstall: + ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} \ + -m ${BINMODE} ${PROG} ${BINDIR}/${PROG} + +dist: + mkdir ../diff-${DIFF_VERSION}/diff + cp ${SRCS} ${MAN} ../diff-${DIFF_VERSION}/diff + +.include <bsd.prog.mk> diff --git a/contrib/libdiff/diff/diff.c b/contrib/libdiff/diff/diff.c new file mode 100644 index 000000000000..eded4163df8d --- /dev/null +++ b/contrib/libdiff/diff/diff.c @@ -0,0 +1,280 @@ +/* Commandline diff utility to test diff implementations. */ +/* + * Copyright (c) 2018 Martin Pieuchot + * Copyright (c) 2020 Neels Hofmeyr <neels@hofmeyr.de> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <err.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> + +#include <arraylist.h> +#include <diff_main.h> +#include <diff_output.h> + +enum diffreg_algo { + DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE = 0, + DIFFREG_ALGO_MYERS_THEN_PATIENCE = 1, + DIFFREG_ALGO_PATIENCE = 2, + DIFFREG_ALGO_NONE = 3, +}; + +__dead void usage(void); +int diffreg(char *, char *, enum diffreg_algo, bool, bool, bool, + int, bool); +FILE * openfile(const char *, char **, struct stat *); + +__dead void +usage(void) +{ + fprintf(stderr, + "usage: %s [-apPQTwe] [-U n] file1 file2\n" + "\n" + " -a Treat input as ASCII even if binary data is detected\n" + " -p Show function prototypes in hunk headers\n" + " -P Use Patience Diff (slower but often nicer)\n" + " -Q Use forward-Myers for small files, otherwise Patience\n" + " -T Trivial algo: detect similar start and end only\n" + " -w Ignore Whitespace\n" + " -U n Number of Context Lines\n" + " -e Produce ed script output\n" + , getprogname()); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int ch, rc; + bool force_text = false; + bool ignore_whitespace = false; + bool show_function_prototypes = false; + bool edscript = false; + int context_lines = 3; + enum diffreg_algo algo = DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE; + + while ((ch = getopt(argc, argv, "apPQTwU:e")) != -1) { + switch (ch) { + case 'a': + force_text = true; + break; + case 'p': + show_function_prototypes = true; + break; + case 'P': + algo = DIFFREG_ALGO_PATIENCE; + break; + case 'Q': + algo = DIFFREG_ALGO_MYERS_THEN_PATIENCE; + break; + case 'T': + algo = DIFFREG_ALGO_NONE; + break; + case 'w': + ignore_whitespace = true; + break; + case 'U': + context_lines = atoi(optarg); + break; + case 'e': + edscript = true; + break; + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + + rc = diffreg(argv[0], argv[1], algo, force_text, ignore_whitespace, + show_function_prototypes, context_lines, edscript); + if (rc != DIFF_RC_OK) { + fprintf(stderr, "diff: %s\n", strerror(rc)); + return 1; + } + return 0; +} + +const struct diff_algo_config myers_then_patience; +const struct diff_algo_config myers_then_myers_divide; +const struct diff_algo_config patience; +const struct diff_algo_config myers_divide; + +const struct diff_algo_config myers_then_patience = (struct diff_algo_config){ + .impl = diff_algo_myers, + .permitted_state_size = 1024 * 1024 * sizeof(int), + .fallback_algo = &patience, +}; + +const struct diff_algo_config myers_then_myers_divide = + (struct diff_algo_config){ + .impl = diff_algo_myers, + .permitted_state_size = 1024 * 1024 * sizeof(int), + .fallback_algo = &myers_divide, +}; + +const struct diff_algo_config patience = (struct diff_algo_config){ + .impl = diff_algo_patience, + /* After subdivision, do Patience again: */ + .inner_algo = &patience, + /* If subdivision failed, do Myers Divide et Impera: */ + .fallback_algo = &myers_then_myers_divide, +}; + +const struct diff_algo_config myers_divide = (struct diff_algo_config){ + .impl = diff_algo_myers_divide, + /* When division succeeded, start from the top: */ + .inner_algo = &myers_then_myers_divide, + /* (fallback_algo = NULL implies diff_algo_none). */ +}; + +const struct diff_algo_config no_algo = (struct diff_algo_config){ + .impl = diff_algo_none, +}; + +/* If the state for a forward-Myers is small enough, use Myers, otherwise first + * do a Myers-divide. */ +const struct diff_config diff_config_myers_then_myers_divide = { + .atomize_func = diff_atomize_text_by_line, + .algo = &myers_then_myers_divide, +}; + +/* If the state for a forward-Myers is small enough, use Myers, otherwise first + * do a Patience. */ +const struct diff_config diff_config_myers_then_patience = { + .atomize_func = diff_atomize_text_by_line, + .algo = &myers_then_patience, +}; + +/* Directly force Patience as a first divider of the source file. */ +const struct diff_config diff_config_patience = { + .atomize_func = diff_atomize_text_by_line, + .algo = &patience, +}; + +/* Directly force Patience as a first divider of the source file. */ +const struct diff_config diff_config_no_algo = { + .atomize_func = diff_atomize_text_by_line, +}; + +int +diffreg(char *file1, char *file2, enum diffreg_algo algo, bool force_text, + bool ignore_whitespace, bool show_function_prototypes, int context_lines, + bool edscript) +{ + char *str1, *str2; + FILE *f1, *f2; + struct stat st1, st2; + struct diff_input_info info = { + .left_path = file1, + .right_path = file2, + }; + struct diff_data left = {}, right = {}; + struct diff_result *result = NULL; + int rc; + const struct diff_config *cfg; + int diff_flags = 0; + + switch (algo) { + default: + case DIFFREG_ALGO_MYERS_THEN_MYERS_DIVIDE: + cfg = &diff_config_myers_then_myers_divide; + break; + case DIFFREG_ALGO_MYERS_THEN_PATIENCE: + cfg = &diff_config_myers_then_patience; + break; + case DIFFREG_ALGO_PATIENCE: + cfg = &diff_config_patience; + break; + case DIFFREG_ALGO_NONE: + cfg = &diff_config_no_algo; + break; + } + + f1 = openfile(file1, &str1, &st1); + f2 = openfile(file2, &str2, &st2); + + if (force_text) + diff_flags |= DIFF_FLAG_FORCE_TEXT_DATA; + if (ignore_whitespace) + diff_flags |= DIFF_FLAG_IGNORE_WHITESPACE; + if (show_function_prototypes) + diff_flags |= DIFF_FLAG_SHOW_PROTOTYPES; + + rc = diff_atomize_file(&left, cfg, f1, str1, st1.st_size, diff_flags); + if (rc) + goto done; + rc = diff_atomize_file(&right, cfg, f2, str2, st2.st_size, diff_flags); + if (rc) + goto done; + + result = diff_main(cfg, &left, &right); +#if 0 + rc = diff_output_plain(stdout, &info, result); +#else + if (edscript) + rc = diff_output_edscript(NULL, stdout, &info, result); + else { + rc = diff_output_unidiff(NULL, stdout, &info, result, + context_lines); + } +#endif +done: + diff_result_free(result); + diff_data_free(&left); + diff_data_free(&right); + if (str1) + munmap(str1, st1.st_size); + if (str2) + munmap(str2, st2.st_size); + fclose(f1); + fclose(f2); + + return rc; +} + +FILE * +openfile(const char *path, char **p, struct stat *st) +{ + FILE *f = NULL; + + f = fopen(path, "r"); + if (f == NULL) + err(2, "%s", path); + + if (fstat(fileno(f), st) == -1) + err(2, "%s", path); + +#ifndef DIFF_NO_MMAP + *p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0); + if (*p == MAP_FAILED) +#endif + *p = NULL; /* fall back on file I/O */ + + return f; +} |