[m-rev.] for post-commit review: io.m style fixes.

Peter Wang novalazy at gmail.com
Thu Oct 6 17:59:32 AEDT 2016


For review if anyone wants.
---

io.m style fixes.

library/io.m:
    Make `file_id_2' return system_error instead of status and error
    message.

    Delete `have_file_ids' in favour of `file_id_2' returning an error
    if unsupported.

    Make `call_system_code' return system_error instead of status and
    error message.

    Improve Erlang `call_system_code' slightly:
      - fix pattern match when exit status is longer than one decimal
      digit - use printf instead of less portable echo -n

    Implement Java `command_line_arguments' directly.

    Delete obsolete fallback predicates `command_line_arguments',
    `build_command_line_args' and `command_line_argument'.

    Make `do_make_temp' and `do_make_temp_directory' return system_error
    instead of status and error message.

    Reorder some code.

diff --git a/library/io.m b/library/io.m
index 7c313eb..5aad394 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1727,10 +1727,6 @@
 :- type file_id.
 :- pred file_id(string::in, io.res(file_id)::out, io::di, io::uo) is det.
 
-    % Succeeds if file_id is implemented on this platform.
-    %
-:- pred have_file_ids is semidet.
-
 %
 % For use by term_io.m:
 %
@@ -2009,13 +2005,12 @@ using System.Security.Principal;
 :- pred read_byte_val(input_stream::in, result_code::out, int::out,
     system_error::out, io::di, io::uo) is det.
 
-    % call_system_code(Command, Status, Success, Message, !IO):
+    % call_system_code(Command, Status, Error, !IO):
     %
     % Invokes the operating system shell with the specified Command.
-    % On success Success = yes and Status is valid. On failure Success = no and
-    % Message will contain the error message.
+    % Status is valid when Error indicates success.
     %
-:- pred call_system_code(string::in, int::out, bool::out, string::out,
+:- pred call_system_code(string::in, int::out, system_error::out,
     io::di, io::uo) is det.
 
     % getenv(Var, Value):
@@ -3738,28 +3733,23 @@ compare_file_id(Result, FileId1, FileId2) :-
 ").
 
 file_id(FileName, Result, !IO) :-
-    ( if have_file_ids then
-        io.file_id_2(FileName, Status, Msg, FileId, !IO),
-        ( if Status = 1 then
+    io.file_id_2(FileName, FileId, Error, !IO),
+    ( if is_error(Error, "cannot get file id: ", IOError) then
+        Result = error(IOError)
+    else
         Result = ok(FileId)
-        else
-            Result = error(io_error(Msg))
-        )
-    else
-        Result = error(make_io_error("io.file_id not implemented " ++
-            "on this platform"))
     ).
 
-:- pred file_id_2(string::in, int::out, string::out, file_id::out,
-    io::di, io::uo) is det.
+:- pred file_id_2(string::in, file_id::out, system_error::out, io::di, io::uo)
+    is det.
 
 :- pragma foreign_proc("C",
-    file_id_2(FileName::in, Status::out, Msg::out,
-        FileId::out, _IO0::di, _IO::uo),
+    file_id_2(FileName::in, FileId::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         does_not_affect_liveness, no_sharing],
 "
-#ifdef MR_HAVE_STAT
+    /* Win32 returns junk in the st_ino field of `struct stat'. */
+#if defined(MR_HAVE_STAT) && !defined(MR_BROKEN_STAT_ST_INO)
   #ifdef MR_WIN32
     struct _stat s;
     int stat_result = _wstat(ML_utf8_to_wide(FileName), &s);
@@ -3771,33 +3761,33 @@ file_id(FileName, Result, !IO) :-
     if (stat_result == 0) {
         FileId.device = s.st_dev;
         FileId.inode = s.st_ino;
-        Msg = MR_string_const("""", 0);
-        Status = 1;
+        Error = 0;
     } else {
-        ML_make_err_msg(errno, ""stat() failed: "", MR_ALLOC_ID, Msg);
-        Status = 0;
+        Error = errno;
     }
 #else
-    MR_fatal_error(""io.file_id_2 called but not supported"");
+    Error = ENOSYS;
 #endif
 ").
 
+:- pragma foreign_proc("C#",
+    file_id_2(_FileName::in, _FileId::out, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+    Error = new System.NotSupportedException(
+        ""io.file_id not supported on this platform"");
+").
+
 :- pragma foreign_proc("Java",
-    file_id_2(_FileName::in, _Status::out, _Msg::out,
-        _FileId::out, _IO0::di, _IO::uo),
+    file_id_2(_FileName::in, _FileId::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
-    // This function should never be called, since have_file_ids will
-    // fail for Java.
-    if (true) { // otherwise Java complains about unreachable stmts.
-        throw new RuntimeException(
-            ""io.file_id_2 called but not supported"");
-    }
+    Error = new java.lang.UnsupportedOperationException(
+        ""io.file_id not supported on this platform"");
 ").
 
 :- pragma foreign_proc("Erlang",
-    file_id_2(FileName::in, Status::out, Msg::out,
-        FileId::out, _IO0::di, _IO::uo),
+    file_id_2(FileName::in, FileId::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         may_not_duplicate],
 "
@@ -3807,38 +3797,13 @@ file_id(FileName, Result, !IO) :-
             MajorDevice = FileInfo#file_info.major_device,
             Inode = FileInfo#file_info.inode,
             FileId = {MajorDevice, Inode},
-            Msg = <<>>,
-            Status = 1;
+            Error = ok;
         {error, Reason} ->
             FileId = null,
-            Msg = list_to_binary(file:format_error(Reason)),
-            Status = 0
+            Error = {error, Reason}
     end
 ").
 
-% Can we retrieve inode numbers on this system.
-have_file_ids :- semidet_fail.
-:- pragma foreign_proc("C",
-    have_file_ids,
-    [promise_pure, will_not_call_mercury, thread_safe, will_not_modify_trail,
-        does_not_affect_liveness, no_sharing],
-"
-#if defined(MR_BROKEN_STAT_ST_INO) || !defined(MR_HAVE_STAT)
-    /* Win32 returns junk in the st_ino field of `struct stat'. */
-    SUCCESS_INDICATOR = MR_FALSE;
-#else
-    SUCCESS_INDICATOR = MR_TRUE;
-#endif
-").
-
-:- pragma foreign_proc("Erlang",
-    have_file_ids,
-    [promise_pure, will_not_call_mercury, thread_safe, will_not_modify_trail,
-        does_not_affect_liveness],
-"
-    SUCCESS_INDICATOR = true
-").
-
 %---------------------------------------------------------------------------%
 
 % A `buffer' is an array of chars.
@@ -5399,15 +5364,15 @@ call_system(Command, Result, !IO) :-
     ).
 
 call_system_return_signal(Command, Result, !IO) :-
-    call_system_code(Command, Code, Success, Msg, !IO),
-    (
-        Success = no,
-        Result = error(io_error(Msg))
-    ;
-        Success = yes,
-        Result = decode_system_command_exit_code(Code)
+    call_system_code(Command, Status, Error, !IO),
+    ( if is_error(Error, "error invoking system command: ", IOError) then
+        Result = error(IOError)
+    else
+        Result = decode_system_command_exit_code(Status)
     ).
 
+%---------------------------------------------------------------------------%
+
 :- type io.error
     --->    io_error(string).       % This is subject to change.
     % Note that we use `io_error' rather than `io.error' because io.print,
@@ -7428,9 +7393,9 @@ is_maybe_win32_error(Error, Prefix, io_error(Message)) :-
 :- pragma foreign_proc("C#",
     make_err_msg(Error::in, Msg0::in, Msg::out),
     [will_not_call_mercury, promise_pure, thread_safe],
-"{
+"
     Msg = System.String.Concat(Msg0, Error.Message);
-}").
+").
 
 :- pragma foreign_proc("Java",
     make_err_msg(Error::in, Msg0::in, Msg::out),
@@ -9699,6 +9664,12 @@ close_binary_output(binary_output_stream(Stream), !IO) :-
 %
 % Miscellaneous predicates
 %
+% XXX Grouping by language is more confusing than helpful.
+%
+
+    % Fallback implementation.
+progname(DefaultProgName, ProgName, !IO) :-
+    ProgName = DefaultProgName.
 
 :- pragma foreign_proc("C",
     progname(DefaultProgname::in, PrognameOut::out, _IO0::di, _IO::uo),
@@ -9784,8 +9755,7 @@ close_binary_output(binary_output_stream(Stream), !IO) :-
 ").
 
 :- pragma foreign_proc("C",
-    call_system_code(Command::in, Status::out, Success::out, Msg::out,
-        _IO0::di, _IO::uo),
+    call_system_code(Command::in, Status::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         does_not_affect_liveness, no_sharing],
 "
@@ -9825,21 +9795,17 @@ close_binary_output(binary_output_stream(Stream), !IO) :-
 
     if (err != 0) {
         /* Spawn failed. */
-        Success = MR_NO;
-        ML_make_err_msg(errno, ""error invoking system command: "",
-            MR_ALLOC_ID, Msg);
+        Error = errno;
     } else {
         /* Wait for the spawned process to exit. */
         do {
             err = waitpid(pid, &st, 0);
         } while (err == -1 && MR_is_eintr(errno));
         if (err == -1) {
-            Success = MR_NO;
-            ML_make_err_msg(errno, ""error invoking system command: "",
-                MR_ALLOC_ID, Msg);
+            Error = errno;
         } else {
             Status = st;
-            Success = MR_YES;
+            Error = 0;
         }
     }
 
@@ -9852,52 +9818,14 @@ close_binary_output(binary_output_stream(Stream), !IO) :-
   #endif
 
     if (Status == -1) {
-        Success = MR_NO;
-        ML_make_err_msg(errno, ""error invoking system command: "",
-            MR_ALLOC_ID, Msg);
+        Error = errno;
     } else {
-        Success = MR_YES;
+        Error = 0;
     }
 
 #endif  /* !MR_THREAD_SAFE || !MR_HAVE_POSIX_SPAWN || !MR_HAVE_ENVIRON */
 ").
 
-:- pragma foreign_proc("Erlang",
-    call_system_code(Command::in, Status::out, Success::out, Msg::out,
-        _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
-        does_not_affect_liveness],
-"
-    % XXX this is bad
-    % 1. the command cannot receive input
-    % 2. output doesn't come out until process finishes
-    % 3. the error code is returned in an inefficient way
-    % 4. standard output and standard error are always tied together
-    %
-    CommandStr = binary_to_list(Command),
-    OutputCode = os:cmd(CommandStr ++ ""; echo -n $?""),
-    case string:rchr(OutputCode, $\\n) of
-        0 ->
-            Code = OutputCode;
-        NL ->
-            {Output, [$\\n, Code]} = lists:split(NL - 1, OutputCode),
-            io:put_chars(Output)
-    end,
-    {Status, []} = string:to_integer(Code),
-    case Status =:= 0 of
-        true ->
-            Msg = <<>>,
-            Success = yes;
-        false ->
-            Msg = <<""error invoking system command"">>,
-            Success = no
-    end
-").
-
-progname(DefaultProgName::in, ProgName::out, IO::di, IO::uo) :-
-    % This is a fall-back for back-ends which don't support the C interface.
-    ProgName = DefaultProgName.
-
 decode_system_command_exit_code(Code0) = Status :-
     decode_system_command_exit_code(Code0, Exited, ExitCode, Signalled,
         Signal),
@@ -9950,6 +9878,8 @@ decode_system_command_exit_code(Status, yes, Status, no, 0).
     #endif
 ").
 
+%---------------------%
+
 :- pragma foreign_proc("C#",
     command_line_arguments(Args::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
@@ -9978,8 +9908,7 @@ decode_system_command_exit_code(Status, yes, Status, no, 0).
 ").
 
 :- pragma foreign_proc("C#",
-    call_system_code(Command::in, Status::out, Success::out, Msg::out,
-        _IO0::di, _IO::uo),
+    call_system_code(Command::in, Status::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io],
 "
     try {
@@ -9995,12 +9924,6 @@ decode_system_command_exit_code(Status, yes, Status, no, 0).
             arguments = """";
         }
 
-        // debugging...
-        // System.Console.Out.WriteLine(
-        //  ""[command = "" + command + ""]"");
-        // System.Console.Out.WriteLine(
-        //  ""[arguments = "" + arguments + ""]"");
-
         System.Diagnostics.Process process = new System.Diagnostics.Process();
         // Never interpret the command as a document to open with whatever
         // application is registered for that document type. This also
@@ -10011,23 +9934,16 @@ decode_system_command_exit_code(Status, yes, Status, no, 0).
         process.Start();
         process.WaitForExit();
         Status = process.ExitCode;
-        Msg = """";
-        Success = mr_bool.YES;
-
-        // debugging...
-        // System.Console.Out.WriteLine(""[exitcode = "" + Status + ""]"");
-
+        Error = null;
     }
     catch (System.Exception e) {
-        Success = mr_bool.NO;
         Status = 1;
-        Msg = e.Message;
-
-        // debugging...
-        // System.Console.Out.WriteLine(""[message = "" + Msg + ""]"");
+        Error = e;
     }
 ").
 
+%---------------------%
+
 :- pragma foreign_proc("Java",
     progname(_Default::in, PrognameOut::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
@@ -10037,90 +9953,35 @@ decode_system_command_exit_code(Status, yes, Status, no, 0).
 ").
 
 :- pragma foreign_proc("Java",
-    get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io,
-        may_not_duplicate],
-"
-    ExitStatus = jmercury.runtime.JavaInternal.exit_status;
-").
-
-:- pragma foreign_proc("Java",
-    set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io,
-        may_not_duplicate],
-"
-    jmercury.runtime.JavaInternal.exit_status = ExitStatus;
-").
-
-:- pragma foreign_proc("Erlang",
     command_line_arguments(Args::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"
-    ArgStrings = init:get_plain_arguments(),
-    Args = lists:map(fun list_to_binary/1, ArgStrings)
-").
-
-:- pragma foreign_proc("Erlang",
-    get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io],
-"
-    'ML_erlang_global_server' ! {get_exit_status, self()},
-    receive
-        {get_exit_status_ack, ExitStatus} ->
-            void
-    end
-").
-
-:- pragma foreign_proc("Erlang",
-    set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io],
-"
-    'ML_erlang_global_server' ! {set_exit_status, ExitStatus}
-").
-
-command_line_arguments(Args, IO, IO) :-
-    build_command_line_args(0, Args).
-
-:- pred build_command_line_args(int::in, list(string)::out) is det.
-
-build_command_line_args(ArgNumber, Args) :-
-    ( if command_line_argument(ArgNumber, Arg) then
-        Args = [Arg | MoreArgs],
-        build_command_line_args(ArgNumber + 1, MoreArgs)
-    else
-        Args = []
-    ).
-
-:- pred command_line_argument(int::in, string::out) is semidet.
-
-command_line_argument(_, "") :-
-    % XXX This predicate is currently only used by the Java implementation,
-    % but to prevent compilation warnings for (eg) the C implementation,
-    % some definition needs to be present.
-    ( if semidet_succeed then
-        error("unexpected call to command_line_argument")
-    else
-        semidet_fail
-    ).
-
-:- pragma foreign_proc("Java",
-    command_line_argument(ArgNum::in, Arg::out),
     [will_not_call_mercury, promise_pure, thread_safe, may_not_duplicate],
 "
     String[] arg_vector = jmercury.runtime.JavaInternal.args;
-
-    if (ArgNum < arg_vector.length && ArgNum >= 0) {
-        Arg = arg_vector[ArgNum];
-        SUCCESS_INDICATOR = true;
-    } else {
-        Arg = null;
-        SUCCESS_INDICATOR = false;
+    Args = list.empty_list();
+    // arg_vector does not include the executable name.
+    for (int i = arg_vector.length - 1; i >= 0; --i) {
+        Args = list.cons(arg_vector[i], Args);
     }
 ").
 
 :- pragma foreign_proc("Java",
-    call_system_code(Command::in, Status::out, Success::out, Msg::out,
-        _IO0::di, _IO::uo),
+    get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io,
+        may_not_duplicate],
+"
+    ExitStatus = jmercury.runtime.JavaInternal.exit_status;
+").
+
+:- pragma foreign_proc("Java",
+    set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io,
+        may_not_duplicate],
+"
+    jmercury.runtime.JavaInternal.exit_status = ExitStatus;
+").
+
+:- pragma foreign_proc("Java",
+    call_system_code(Command::in, Status::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, may_not_duplicate],
 "
     boolean has_sh;
@@ -10159,8 +10020,7 @@ command_line_argument(_, "") :-
         stderr.start();
 
         Status = process.waitFor();
-        Success = bool.YES;
-        Msg     = null;
+        Error = null;
 
         // The stdin StreamPipe is killed off after the Process is finished
         // so as not to waste CPU cycles with a pointless thread.
@@ -10181,14 +10041,64 @@ command_line_argument(_, "") :-
         }
     } catch (java.lang.Exception e) {
         Status  = 1;
-        Success = bool.NO;
-        Msg = e.getMessage();
-        if (Msg == null) {
-            Msg = ""null"";
-        }
+        Error = e;
     }
 ").
 
+%---------------------%
+
+:- pragma foreign_proc("Erlang",
+    command_line_arguments(Args::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+    ArgStrings = init:get_plain_arguments(),
+    Args = lists:map(fun list_to_binary/1, ArgStrings)
+").
+
+:- pragma foreign_proc("Erlang",
+    get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io],
+"
+    'ML_erlang_global_server' ! {get_exit_status, self()},
+    receive
+        {get_exit_status_ack, ExitStatus} ->
+            void
+    end
+").
+
+:- pragma foreign_proc("Erlang",
+    set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io],
+"
+    'ML_erlang_global_server' ! {set_exit_status, ExitStatus}
+").
+
+:- pragma foreign_proc("Erlang",
+    call_system_code(Command::in, Status::out, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
+        does_not_affect_liveness],
+"
+    % XXX this is just a hack
+    % 0. assumes unix shell
+    % 1. the command cannot receive input
+    % 2. output doesn't come out until process finishes
+    % 3. the error code is returned in an inefficient way
+    % 4. standard output and standard error are always tied together
+    % 5. the command should be bracketed/sanitised
+    %
+    CommandStr = binary_to_list(Command),
+    OutputAndCode = os:cmd(CommandStr ++ ""; printf '\\n%d' $?""),
+    case string:rchr(OutputAndCode, $\\n) of
+        0 ->
+            Code = OutputAndCode;
+        NL ->
+            {Output, [$\\n | Code]} = lists:split(NL - 1, OutputAndCode),
+            io:put_chars(Output)
+    end,
+    {Status, []} = string:to_integer(Code),
+    Error = ok
+").
+
 %---------------------------------------------------------------------------%
 
 % io.getenv and io.setenv.
@@ -10339,13 +10249,11 @@ make_temp(Name, !IO) :-
 
 make_temp_file(Dir, Prefix, Suffix, Result, !IO) :-
     do_make_temp(Dir, Prefix, Suffix, char_to_string(dir.directory_separator),
-        Name, Okay, Message, !IO),
-    (
-        Okay = yes,
+        Name, Error, !IO),
+    ( if is_error(Error, "error creating temporary file: ", IOError) then
+        Result = error(IOError)
+    else
         Result = ok(Name)
-    ;
-        Okay = no,
-        Result = error(make_io_error(Message))
     ).
 
 make_temp(Dir, Prefix, Name, !IO) :-
@@ -10363,18 +10271,15 @@ make_temp_directory(Result, !IO) :-
 
 make_temp_directory(Dir, Prefix, Suffix, Result, !IO) :-
     do_make_temp_directory(Dir, Prefix, Suffix,
-        char_to_string(dir.directory_separator), DirName, Okay, Message, !IO),
-    (
-        Okay = yes,
+        char_to_string(dir.directory_separator), DirName, Error, !IO),
+    ( if is_error(Error, "error creating temporary directory: ", IOError) then
+        Result = error(IOError)
+    else
         Result = ok(DirName)
-    ;
-        Okay = no,
-        Result = error(make_io_error(Message))
     ).
 
 %---------------------------------------------------------------------------%
 
-
 :- pragma foreign_decl("Java", local,
 "
 import java.io.File;
@@ -10411,8 +10316,8 @@ import java.util.Random;
     }
 ").
 
-:- pred do_make_temp(string::in, string::in, string::in,
-    string::in, string::out, bool::out, string::out, io::di, io::uo) is det.
+:- pred do_make_temp(string::in, string::in, string::in, string::in,
+    string::out, system_error::out, io::di, io::uo) is det.
 
 % XXX The code for io.make_temp assumes POSIX. It uses the functions open(),
 % close(), and getpid() and the macros EEXIST, O_WRONLY, O_CREAT, and O_EXCL.
@@ -10438,9 +10343,10 @@ import java.util.Random;
 
 :- pragma foreign_proc("C",
     do_make_temp(Dir::in, Prefix::in, Suffix::in, Sep::in, FileName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io,
-        does_not_affect_liveness],
+        Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure,
+        not_thread_safe, % due to ML_io_tempnam_counter
+        tabled_for_io, does_not_affect_liveness],
 "
 #ifdef MR_HAVE_MKSTEMP
     int err, fd;
@@ -10453,20 +10359,15 @@ import java.util.Random;
         Dir, Sep, Prefix);
     fd = mkstemp(FileName);
     if (fd == -1) {
-        ML_make_err_msg(errno, ""error opening temporary file: "", MR_ALLOC_ID,
-            ErrorMessage);
-        Okay = MR_NO;
+        Error = errno;
     } else {
         do {
             err = close(fd);
         } while (err == -1 && MR_is_eintr(errno));
         if (err == 0) {
-            ErrorMessage = MR_make_string_const("""");
-            Okay = MR_YES;
+            Error = 0;
         } else {
-            ML_make_err_msg(errno, ""error closing temporary file: "",
-                MR_ALLOC_ID, ErrorMessage);
-            Okay = MR_NO;
+            Error = errno;
         }
     }
 #else
@@ -10512,20 +10413,15 @@ import java.util.Random;
     } while (fd == -1 && errno == EEXIST &&
         num_tries < ML_MAX_TEMPNAME_TRIES);
     if (fd == -1) {
-        ML_make_err_msg(errno, ""error opening temporary file: "", MR_ALLOC_ID,
-            ErrorMessage);
-        Okay = MR_NO;
+        Error = errno;
     }  else {
         do {
             err = close(fd);
         } while (err == -1 && MR_is_eintr(errno));
         if (err == 0) {
-            ErrorMessage = MR_make_string_const("""");
-            Okay = MR_YES;
+            Error = 0;
         } else {
-            ML_make_err_msg(errno, ""error closing temporary file: "",
-                MR_ALLOC_ID, ErrorMessage);
-            Okay = MR_NO;
+            Error = errno;
         }
     }
 #endif
@@ -10533,25 +10429,21 @@ import java.util.Random;
 
 :- pragma foreign_proc("C#",
     do_make_temp(_Dir::in, _Prefix::in, _Suffix::in, _Sep::in, FileName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+        Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
     try {
         FileName = System.IO.Path.GetTempFileName();
-        Okay = mr_bool.YES;
-        ErrorMessage = """";
-    }
-    catch (System.Exception e)
-    {
+        Error = null;
+    } catch (System.Exception e) {
         FileName = """";
-        Okay = mr_bool.NO;
-        ErrorMessage = e.Message;
+        Error = e;
     }
-}").
+").
 
 :- pragma foreign_proc("Java",
     do_make_temp(Dir::in, Prefix::in, Suffix::in, _Sep::in, FileName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+        Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         may_not_duplicate],
 "
@@ -10567,23 +10459,20 @@ import java.util.Random;
         new_file = new File(new File(Dir), makeTempName(Prefix, Suffix));
         if (new_file.createNewFile()) {
             FileName = new_file.getAbsolutePath();
-            Okay = bool.YES;
-            ErrorMessage = """";
+            Error = null;
         } else {
             FileName = """";
-            Okay = bool.NO;
-            ErrorMessage = ""Could not create file"";
+            Error = new java.io.IOException(""Could not create file"");
         }
     } catch (IOException e) {
         FileName = """";
-        Okay = bool.NO;
-        ErrorMessage = e.toString();
+        Error = e;
     }
 ").
 
 :- pragma foreign_proc("Erlang",
     do_make_temp(Dir::in, Prefix::in, Suffix::in, Sep::in, FileName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+        Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io,
         does_not_affect_liveness],
 "
@@ -10612,33 +10501,32 @@ import java.util.Random;
 
     case
         mercury__io:'ML_do_make_temp_2'(DirStr, PrefixStr, SuffixStr, SepStr,
-            MaxTries, Seed)
+            MaxTries, Seed, eio)
     of
         {ok, FileName0} ->
             FileName = list_to_binary(FileName0),
-            Okay = {yes},
-            ErrorMessage = <<>>;
+            Error = ok;
         {error, Reason} ->
             FileName = <<>>,
-            Okay = {no},
-            ErrorMessage = list_to_binary(Reason)
+            Error = {error, Reason}
     end
 ").
 
 :- pragma foreign_decl("Erlang", local, "
-    -export(['ML_do_make_temp_2'/6]).
+    -export(['ML_do_make_temp_2'/7]).
 ").
 :- pragma foreign_code("Erlang", "
-    'ML_do_make_temp_2'(_, _, _, _, 0, _) ->
-        {error, ""error opening temporary file""};
-    'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep, Tries, Seed0) ->
+    'ML_do_make_temp_2'(_Dir, _Prefix, _Suffix, _Sep, 0, _Seed, LastError) ->
+        {error, LastError};
+    'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep, Tries, Seed0, LastError) ->
         {R1, Seed1} = random:uniform_s(16#1000, Seed0),
         {R2, Seed}  = random:uniform_s(16#1000, Seed1),
         FileName = lists:flatten(io_lib:format(""~s~s~s~3.16.0B.~3.16.0B~s"",
             [Dir, Sep, Prefix, R1, R2, Suffix])),
         case filelib:is_file(FileName) of
             true ->
-                'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep, Tries - 1, Seed);
+                'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep, Tries - 1, Seed,
+                    eexist);
             false ->
                 case file:open(FileName, [write, {encoding, utf8}]) of
                     {ok, IoDevice} ->
@@ -10646,11 +10534,11 @@ import java.util.Random;
                             ok ->
                                 {ok, FileName};
                             {error, Reason} ->
-                                {error, file:format_error(Reason)}
+                                {error, Reason}
                         end;
-                    {error, _} ->
+                    {error, Reason} ->
                         'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep,
-                            Tries - 1, Seed)
+                            Tries - 1, Seed, Reason)
                 end
         end.
 ").
@@ -10658,12 +10546,12 @@ import java.util.Random;
 %-----------------------------------------------------------------------%
 
 :- pred do_make_temp_directory(string::in, string::in, string::in, string::in,
-    string::out, bool::out, string::out, io::di, io::uo) is det.
+    string::out, system_error::out, io::di, io::uo) is det.
 
 :- pragma foreign_proc("C",
     do_make_temp_directory(Dir::in, Prefix::in, Suffix::in, Sep::in,
-        DirName::out, Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io,
+        DirName::out, Error::out, _IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io,
         does_not_affect_liveness],
 "
 #ifdef MR_HAVE_MKDTEMP
@@ -10677,24 +10565,19 @@ import java.util.Random;
         Dir, Sep, Prefix);
     DirName = mkdtemp(DirName);
     if (DirName == NULL) {
-        ML_make_err_msg(errno, ""error creating temporary directory: "",
-            MR_ALLOC_ID, ErrorMessage);
-        Okay = MR_NO;
+        Error = errno;
     } else {
-        ErrorMessage = MR_make_string_const("""");
-        Okay = MR_YES;
+        Error = 0;
     }
 #else
-    Okay = MR_NO;
-    ErrorMessage =
-        MR_make_string_const(""Your system does not have mkdtemp"");
+    Error = ENOSYS;
     DirName = MR_make_string_const("""");
 #endif /* HAVE_MKDTEMP */
 ").
 
 :- pragma foreign_proc("C#",
     do_make_temp_directory(Dir::in, _Prefix::in, _Suffix::in, _Sep::in,
-        DirName::out, Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+        DirName::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "{
     try
@@ -10722,8 +10605,7 @@ import java.util.Random;
                     )
                 );
                 Directory.CreateDirectory(DirName, security);
-                ErrorMessage = string.Empty;
-                Okay = mr_bool.YES;
+                Error = null;
                 break;
 
 #if __MonoCS__
@@ -10732,38 +10614,34 @@ import java.util.Random;
                 int errorNo = ML_sys_mkdir(DirName, 0x7 << 6);
                 if (errorNo == 0)
                 {
-                    ErrorMessage = string.Empty;
-                    Okay = mr_bool.YES;
+                    Error = null;
                 }
                 else
                 {
-                    ErrorMessage = string.Format(
+                    Error = new System.Exception(string.Format(
                         ""Creating directory {0} failed with: {1:X}"",
-                            DirName, errorNo);
-                    Okay = mr_bool.NO;
+                        DirName, errorNo));
                 }
                 break;
 #endif
 
             default:
-                Okay = mr_bool.NO;
-                ErrorMessage =
+                Error = new System.Exception(
                     ""Changing folder permissions is not supported for: "" +
-                    Environment.OSVersion;
+                    Environment.OSVersion);
                 break;
         }
     }
     catch (System.Exception e)
     {
         DirName = string.Empty;
-        Okay = mr_bool.NO;
-        ErrorMessage = e.Message;
+        Error = e;
     }
 }").
 
 :- pragma foreign_proc("Java",
     do_make_temp_directory(Dir::in, Prefix::in, Suffix::in, _Sep::in,
-        DirName::out, Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+        DirName::out, Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         may_not_duplicate],
 "
@@ -10778,12 +10656,10 @@ import java.util.Random;
     new_dir = new File(new File(Dir), makeTempName(Prefix, Suffix));
     if (new_dir.mkdir()) {
         DirName = new_dir.getAbsolutePath();
-        Okay = bool.YES;
-        ErrorMessage = """";
+        Error = null;
     } else {
         DirName = """";
-        Okay = bool.NO;
-        ErrorMessage = ""Coudln't create directory"";
+        Error = new java.io.IOException(""Couldn't create directory"");
     }
 ").
 


More information about the reviews mailing list