Cat filter (Mercury)

From LiteratePrograms

Jump to: navigation, search

This is an example of basic input output handling from the compiler examples (source distrib).

>>Simple implementation of the standard unix cat filter: copy input files (or stdin, if no input files) to stdout.

Author acknowledgement. From the original file:

% This source file is hereby placed in the public domain.  -fjh (the author).

Contents

Main block

Command line arguments (list(string)) are never taken from the main entry point which only take as arguments the IO states of the world.

The "!X" construct encloses two variables, the initial "!.X" and final "!:X" states of a state variable.

<<main>>=
main(!IO) :-
                    io.command_line_arguments(Args, !IO),
                    ( 
                    /* if Args is empty then process stdin */
                    Args = [] -> cat(!IO)
                    ;
                    /* else */     
                    cat_file_list(Args, !IO)
                    ).

Process command line filename sequence

This routine takes as parameter the command line argument list of strings, plus the IO states.

<<process_cmd_line_filename_seq>>=
/**
* @param Files list of filenames
* @param !IO  I/O initial and final states
*/
:- pred cat_file_list(list(string)::in, io::di, io::uo) is det.
cat_file_list([], !IO).
cat_file_list([File | Files], !IO) :-
                    cat_file(File, !IO),
                    cat_file_list(Files, !IO).

Process one file

Note: io.open_input Result parameter is of type io.res( io.input_stream)

where type io.res is

:- type io__res(T)
	--->	ok(T)
	;	error(io__error).
<<process_one_file>>=
/**
* @param File filename
* @param !IO state of the world
*/
:- pred cat_file(string::in, io::di, io::uo) is det.
cat_file(File, !IO) :-
                    io.open_input(File, Result, !IO),
                    (
                    /* case Result=ok */
                    Result = ok(Stream),
                    cat_stream(Stream, !IO),
                    io.close_input(Stream, !IO)
                    ;
                    /* case Result=error */
                    Result = error(Error),
                    io.progname("cat", Progname, !IO),
                    io.error_message(Error, Message),
                    io.write_strings([
                    Progname, ": ",
                    "error opening file `", File, "' for input:\n\t",
                    Message, "\n"
                    ], !IO)
                    ).

Process file stream

<<process_file_stream>>=
:- pred cat_stream(io.input_stream::in, io::di, io::uo) is det.
cat_stream(Stream, !IO) :-
                    io.set_input_stream(Stream, _OldStream, !IO),
                    cat(!IO).

Process input stream recursively, on a per line basis

Note: io.read_line_as_string Result parameter is of type io.result( string)

:- type io__result(T)
	--->	ok(T)
	;	eof
	;	error(io__error).
<<process_input_stream>>=
:- pred cat(io::di, io::uo) is det.
cat(!IO) :-
                    io.read_line_as_string(Result, !IO),
                    (
                    /* case Result=eof */
                    Result = eof
                    ;
                    /* case Result=error */
                    Result = error(Error),
                    io.error_message(Error, Message),
                    io.input_stream_name(StreamName, !IO),
                    io.progname("cat", ProgName, !IO),
                    io.write_strings([
                    ProgName, ": ",
                    "error reading input file `", StreamName, "': \n\t",
                    Message, "\n"
                    ], !IO)
                    ;
                    /* case Result=ok */
                    Result = ok(Line),
                    io.write_string(Line, !IO),
                    cat(!IO)
                    ).

Enclosing module

<<cat.m>>=
%-----------------------------------------------------------------------------%

:- module cat.
% Simple implementation of the standard unix `cat' filter:
% copy input files (or stdin, if no input files) to stdout.

% This source file is hereby placed in the public domain.  -fjh (the author).

%-----------------------------------------------------------------------------%

:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
%-----------------------------------------------------------------------------%

:- implementation.
:- import_module string, list, char.
main
process_cmd_line_filename_seq
process_one_file
process_file_stream
process_input_stream
%-----------------------------------------------------------------------------%

Compile and run

  1. Compile cat.m
  2. Run cat
mmc cat.m
cat testfile1 testfile2
>testfile1 contents
>testfile2 contents
cat unexistant_filename
>cat: error opening file 'unexistant_filename' for input:
>             can't open input file: No such file or directory
Views
Navigation