Cat filter (Mercury)
From LiteratePrograms
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
- Compile cat.m
- 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