head	1.1;
access;
symbols;
locks; strict;
comment	@# @;


1.1
date	2013.01.12.01.31.20;	author agc;	state Exp;
branches;
next	;


desc
@@


1.1
log
@Abstract the I/O routines within netdiff to work with either areas of
memory (mmap'ed or allocated), or with stdio; use the appropriate
implementation automatically.  This doesn't change comparisons which
use normal file I/O through stdio in any way - all of the existing
tests continue to pass; however, in addition, it enables the use of
the same comparison functionality on areas of memory.

Using the abstracted I/O, add a diff_mem() function to compare two
areas of memory.  Within the comparison, unless labels are provided
for each area of memory, any netdiff output will be labelled "lhs" and
"rhs".  The mtime for comparison output is taken to be the time at
which the comparison was started, and is the same for both areas of
memory.

Together with the function which retrieves comparison output in
memory, this allows us to do diff comparisons without hitting any file
system at all.

Directory comparisons continue to function in exactly the same way.

Add an example program called memdiff (again, not installed), which
uses mmap to read its input files, diff_mem() to compare the memory,
and diff_get_diffs() to retrieve the differences, all completely in
memory.  Add tests for this program, including filters so that we
don't check the mtimes on the areas of memory compared.

Regular files can still be compared using diff_file(), or the
higher-level difference(), although these will not be as quick as the
mmap()/diff_mem()/diff_get_diffs() combination.
@
text
@/*-
 * Copyright (c) 2013 Alistair Crooks <agc@@NetBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

typedef struct f_t {
	char	*name;
	char	*mapped;
	FILE	*fp;
	size_t	 size;
} f_t;

static int
finit(f_t *file, const char *name)
{
	struct stat	st;

	memset(file, 0x0, sizeof(*file));
	if ((file->fp = fopen(name, "r")) == NULL) {
		return 0;
	}
	fstat(fileno(file->fp), &st);
	file->size = st.st_size;
	file->mapped = mmap(NULL, file->size, PROT_READ, MAP_SHARED, fileno(file->fp), 0);
	if (file->mapped == MAP_FAILED) {
		return 0;
	}
	file->name = strdup(name);
	return 1;
}

static void
fend(f_t *f)
{
	free(f->name);
	munmap(f->mapped, f->size);
	fclose(f->fp);
	memset(f, 0x0, sizeof(*f));
}

static int
difffile(const char *filename1, const char *filename2)
{
	FILE	*pp;
	char	 buf[2048]; // XXX
	char	 cmd[2048]; // XXX
	f_t	 f[2];

	finit(&f[0], filename1);
	finit(&f[1], filename2);
	snprintf(cmd, sizeof(cmd), "diff %s %s", filename1, filename2);
	if ((pp = popen(cmd, "r")) == NULL) {
		return 0;
	}
	while (fgets(buf, sizeof(buf), pp) != NULL) {
		printf("%s", buf);
	}
	pclose(pp);
	fend(&f[0]);
	fend(&f[1]);
	return 1;
}

/*
a long and interesting comment.

multiple lines.

very informative
*/

int
main(int argc, char **argv)
{
	int	i;

	while ((i = getopt(argc, argv, "")) != -1) {
	}
	if (argc - optind < 2) {
		errx(EXIT_FAILURE, "Usage: agcdiff file1 file2");
	}
	difffile(argv[optind], argv[optind + 1]);
	exit(EXIT_SUCCESS);
}
@
