Files
mercury/samples/diff/diff.m
Peter Wang 8da4853b49 Update programs for getopt changes.
benchmarks/progs/icfp2000_par/main.m:
benchmarks/progs/mandelbrot/mandelbrot.m:
benchmarks/tools/log_to_r/log_to_r.m:
extras/align_right/align_right.m:
extras/error/error.m:
extras/gator/evolve.m:
extras/moose/options.m:
samples/concurrency/midimon/midimon.m:
samples/diff/diff.m:
samples/muz/muz.m:
    Conform to getopt.process_options now returning structured errors
    instead of strings.
2020-10-26 16:24:11 +11:00

179 lines
5.8 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
%-----------------------------------------------------------------------------%
% Copyright (C) 1995-1998, 2006 The University of Melbourne.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% Main authors: bromage, Marnix Klooster <marnix@worldonline.nl>
%
% Something very similar to the standard diff utility. Sort of. :-)
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module diff.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module diff_out.
:- import_module file.
:- import_module filter.
:- import_module globals.
:- import_module match.
:- import_module myers.
:- import_module options.
:- import_module getopt.
:- import_module list.
:- import_module maybe.
%-----------------------------------------------------------------------------%
main(!IO) :-
io.command_line_arguments(Args0, !IO),
options.get_option_ops(OptionOps),
getopt.process_options(OptionOps, Args0, Args, Result0),
Result1 = convert_to_maybe_option_table(Result0),
postprocess_options(Result1, Result, !IO),
(
Result = yes(Msg),
usage_error(Msg, !IO)
;
Result = no,
globals.io_get_output_style(OutputStyle, !IO),
( if OutputStyle = help_only then
usage(!IO)
else if OutputStyle = version_only then
version(!IO)
else
main_2(Args, !IO)
)
).
%-----------------------------------------------------------------------------%
:- pred usage_error(string::in, io::di, io::uo) is det.
usage_error(Msg, !IO) :-
io.progname_base("diff", ProgName, !IO),
io.stderr_stream(StdErr, !IO),
io.write_strings(StdErr, [ProgName, ": ", Msg, "\n"], !IO),
io.set_exit_status(1, !IO),
usage(!IO).
:- pred usage_io_error(io.error::in, io::di, io::uo) is det.
usage_io_error(Error, !IO) :-
io.error_message(Error, Msg),
usage_error(Msg, !IO).
:- pred usage(io::di, io::uo) is det.
usage(!IO) :-
io.write_string("Usage: diff [options] from-file to-file\n\n", !IO),
options_help(!IO).
:- pred version(io::di, io::uo) is det.
version(!IO) :-
io.write_string("diff - Mercury diff version 0.4\n", !IO).
%-----------------------------------------------------------------------------%
% main_2 analyses the command-line arguments which are not options
% and calls diff.do_diff.
%
:- pred main_2(list(string)::in, io::di, io::uo) is det.
main_2(Args, !IO) :-
(
Args = [],
usage_error("missing operand", !IO)
;
Args = [_],
usage_error("missing operand", !IO)
;
Args = [_, _, _ | _],
usage_error("too many operands", !IO)
;
Args = [Fname1, Fname2],
( if Fname1 = Fname2 then
% Not sure why anyone would want to diff two
% files with the same name, but just in case ...
( if Fname1 = "-" then
file.read_input(Fname1, Contents1, !IO),
Contents1 = Contents2
else
file.read_file(Fname1, Contents1, !IO),
Contents1 = Contents2
)
else
% If either file is "-", simply use standard input.
% (Note: Both can't be "-" since that was dealt with
% in the previous case.)
( if Fname1 = "-" then
file.read_input(Fname1, Contents1, !IO),
file.read_file(Fname2, Contents2, !IO)
else if Fname2 = "-" then
file.read_file(Fname1, Contents1, !IO),
file.read_input(Fname2, Contents2, !IO)
else
% Otherwise read the files normally.
file.read_file(Fname1, Contents1, !IO),
file.read_file(Fname2, Contents2, !IO)
)
),
% Now do the diff.
(
Contents1 = ok(File1),
(
Contents2 = ok(File2),
diff.do_diff(File1, File2, !IO)
;
Contents2 = error(Msg),
usage_io_error(Msg, !IO)
)
;
Contents1 = error(Msg),
usage_io_error(Msg, !IO)
)
).
%-----------------------------------------------------------------------------%
% do_diff takes the files plus all the command line options
% and determines what to do with them.
%
:- pred do_diff(file::in, file::in, io::di, io::uo) is det.
do_diff(File1, File2, !IO) :-
% There are four passes:
%
% - build_matches determines which lines from the input files match
% (using the appropriate command-line options).
% - diff_by_myers takes the matches produced and computes a diff between
% them.
% - filter_diff analyses the diff, filtering out any edits which the user
% said that they didn't want to see (using the appropriate command-line
% options).
% - display_diff outputs the diff in whatever output format the user chose.
%
build_matches(File1, File2, FileX, FileY, !IO),
diff_by_myers(FileX, FileY, Diff0, !IO),
filter_diff(File1, File2, Diff0, Diff, !IO),
display_diff(File1, File2, Diff, !IO).
%-----------------------------------------------------------------------------%
:- end_module diff.
%-----------------------------------------------------------------------------%