[m-rev.] for review: Allow user code to create io.error values with system errors.

Peter Wang novalazy at gmail.com
Mon Aug 29 14:24:37 AEST 2022


library/io.m:
    Move make_io_error_from_system_error to public interface.

    Add make_io_error_from_windows_error.

    Rename is_maybe_win32_error to is_error_maybe_win32.
    Make it take an argument to indicate whether the error is a Win32
    error code.

    Make make_io_error_from_maybe_win32_error (an internal predicate)
    take an argument to indicate whether the error is a Win32
    error code.

library/dir.m:
    Conform to changes.

NEWS:
    Announce recent system error related changes.
---
 NEWS          |   7 +++
 library/dir.m | 102 ++++++++++++++++++++++++++--------------
 library/io.m  | 128 ++++++++++++++++++++++++++++++--------------------
 3 files changed, 149 insertions(+), 88 deletions(-)

diff --git a/NEWS b/NEWS
index d898dadb7..10b6dea53 100644
--- a/NEWS
+++ b/NEWS
@@ -101,6 +101,13 @@ Changes to the Mercury standard library
 
 * The following predicates have been added:
 
+    - pred `make_io_error_from_system_error/5`
+    - pred `make_io_error_from_windows_error/5`
+    - pred `get_system_error/2`
+    - pred `get_errno_error/2`
+    - pred `get_windows_error/2`
+    - pred `get_exception_object_error/2`
+    - pred `get_system_error_name/2`
     - pred `write_binary_string_utf8/3`
     - pred `write_binary_string_utf8/4`
 
diff --git a/library/dir.m b/library/dir.m
index c93c445d9..5a4044e2d 100644
--- a/library/dir.m
+++ b/library/dir.m
@@ -1043,7 +1043,7 @@ make_directory(PathName, Result, !IO) :-
     io::di, io::uo) is det.
 
 make_directory_or_check_exists(DirName, Result, !IO) :-
-    make_single_directory_2(DirName, MakeDirStatus, MaybeWin32Error, !IO),
+    make_single_directory_2(DirName, MakeDirStatus, Error, IsWin32Error, !IO),
     (
         MakeDirStatus = ok,
         Result = ok
@@ -1053,7 +1053,7 @@ make_directory_or_check_exists(DirName, Result, !IO) :-
         ( if TypeResult = ok(directory) then
             check_dir_accessibility(DirName, Result, !IO)
         else
-            make_io_error_from_maybe_win32_error(MaybeWin32Error,
+            make_io_error_from_maybe_win32_error(Error, IsWin32Error,
                 "cannot create directory: ", IOError, !IO),
             Result = error(IOError)
         )
@@ -1062,7 +1062,7 @@ make_directory_or_check_exists(DirName, Result, !IO) :-
         check_dir_accessibility(DirName, Result, !IO)
     ;
         MakeDirStatus = error,
-        make_io_error_from_maybe_win32_error(MaybeWin32Error,
+        make_io_error_from_maybe_win32_error(Error, IsWin32Error,
             "cannot create directory: ", IOError, !IO),
         Result = error(IOError)
     ).
@@ -1182,7 +1182,7 @@ make_directory_including_parents(DirName, Result, !IO) :-
 %---------------------------------------------------------------------------%
 
 make_single_directory(DirName, Result, !IO) :-
-    make_single_directory_2(DirName, Status, MaybeWin32Error, !IO),
+    make_single_directory_2(DirName, Status, Error, IsWin32Error, !IO),
     (
         Status = ok,
         Result = ok
@@ -1191,7 +1191,7 @@ make_single_directory(DirName, Result, !IO) :-
         ; Status = dir_exists
         ; Status = error
         ),
-        make_io_error_from_maybe_win32_error(MaybeWin32Error,
+        make_io_error_from_maybe_win32_error(Error, IsWin32Error,
             "cannot create directory: ", IOError, !IO),
         Result = error(IOError)
     ).
@@ -1210,11 +1210,11 @@ make_single_directory(DirName, Result, !IO) :-
     [prefix("ML_MAKE_SINGLE_DIRECTORY_"), uppercase]).
 
 :- pred make_single_directory_2(string::in, make_single_directory_status::out,
-    io.system_error::out, io::di, io::uo) is det.
+    io.system_error::out, bool::out, io::di, io::uo) is det.
 
 :- pragma foreign_proc("C",
     make_single_directory_2(DirName::in, Status::out, Error::out,
-        _IO0::di, _IO::uo),
+        IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         will_not_modify_trail, does_not_affect_liveness, may_not_duplicate],
 "
@@ -1230,6 +1230,7 @@ make_single_directory(DirName, Result, !IO) :-
             Status = ML_MAKE_SINGLE_DIRECTORY_ERROR;
         }
     }
+    IsWin32Error = MR_YES;
 #elif defined(MR_HAVE_MKDIR)
     if (mkdir(DirName, 0777) == 0) {
         Status = ML_MAKE_SINGLE_DIRECTORY_OK;
@@ -1243,15 +1244,17 @@ make_single_directory(DirName, Result, !IO) :-
         }
       #endif // EEXIST
     }
+    IsWin32Error = MR_NO
 #else // !MR_WIN32 && !MR_HAVE_MKDIR
     Status = ML_MAKE_SINGLE_DIRECTORY_ERROR;
     Error = ENOSYS;
+    IsWin32Error = MR_NO
 #endif
 ").
 
 :- pragma foreign_proc("C#",
     make_single_directory_2(DirName::in, Status::out, Error::out,
-        _IO0::di, _IO::uo),
+        IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
     try {
@@ -1279,11 +1282,12 @@ make_single_directory(DirName, Result, !IO) :-
         Status = dir.ML_MAKE_SINGLE_DIRECTORY_ERROR;
         Error = e;
     }
+    IsWin32Error = mr_bool.NO;
 ").
 
 :- pragma foreign_proc("Java",
     make_single_directory_2(DirName::in, Status::out, Error::out,
-        _IO0::di, _IO::uo),
+        IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         may_not_duplicate],
 "
@@ -1312,6 +1316,7 @@ make_single_directory(DirName, Result, !IO) :-
         Status = dir.ML_MAKE_SINGLE_DIRECTORY_ERROR;
         Error = e;
     }
+    IsWin32Error = bool.NO;
 ").
 
 %---------------------------------------------------------------------------%
@@ -1641,6 +1646,7 @@ check_for_symlink_loop(DirName, SymLinkParent, ParentIds0, MaybeLoop, !IO) :-
 
 open(DirName, Result, !IO) :-
     ( if have_win32 then
+        % XXX This call to check_dir_readable seems to be redundant.
         check_dir_readable(DirName, ReadabilityResult, !IO),
         (
             ReadabilityResult = mfe_ok(_),
@@ -1659,23 +1665,23 @@ open(DirName, Result, !IO) :-
     io::di, io::uo) is det.
 
 open_2(DirName, DirPattern, Result, !IO) :-
-    open_3(DirName, DirPattern, DirStream, MaybeWin32Error, !IO),
-    is_maybe_win32_error(MaybeWin32Error, "cannot open directory: ",
+    open_3(DirName, DirPattern, DirStream, Error, IsWin32Error, !IO),
+    is_error_maybe_win32(Error, IsWin32Error, "cannot open directory: ",
         MaybeIOError, !IO),
     (
-        MaybeIOError = yes(Error),
-        Result = mfe_error(file_error(DirName, file_open, Error))
+        MaybeIOError = yes(IOError),
+        Result = mfe_error(file_error(DirName, file_open, IOError))
     ;
         MaybeIOError = no,
         Result = mfe_ok(DirStream)
     ).
 
-:- pred open_3(string::in, string::in, dir.stream::out,
-    io.system_error::out, io::di, io::uo) is det.
+:- pred open_3(string::in, string::in, dir.stream::out, io.system_error::out,
+    bool::out, io::di, io::uo) is det.
 
 :- pragma foreign_proc("C",
     open_3(DirName::in, DirPattern::in, DirStream::out, Error::out,
-        _IO0::di, _IO::uo),
+        IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         will_not_modify_trail, does_not_affect_liveness, may_not_duplicate],
 "
@@ -1695,6 +1701,7 @@ open_2(DirName, DirPattern, Result, !IO) :-
         Error = 0;
         DirStream->pending_entry = ML_wide_to_utf8(file_data.cFileName, MR_ALLOC_ID);
     }
+    IsWin32Error = MR_YES;
 
 #elif defined(MR_HAVE_OPENDIR) && defined(MR_HAVE_READDIR) && \\
         defined(MR_HAVE_CLOSEDIR)
@@ -1705,16 +1712,18 @@ open_2(DirName, DirPattern, Result, !IO) :-
     } else {
         Error = 0;
     }
+    IsWin32Error = MR_NO;
 
 #else // !MR_WIN32 && !(MR_HAVE_OPENDIR etc.)
     DirStream = NULL;
     Error = ENOSYS;
+    IsWin32Error = MR_NO;
 #endif
 ").
 
 :- pragma foreign_proc("C#",
     open_3(DirName::in, _DirPattern::in, DirStream::out, Error::out,
-        _IO0::di, _IO::uo),
+        IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_modify_trail, promise_pure, tabled_for_io, thread_safe],
 "
     try {
@@ -1725,11 +1734,12 @@ open_2(DirName, DirPattern, Result, !IO) :-
         DirStream = null;
         Error = e;
     }
+    IsWin32Error = mr_bool.NO;
 ").
 
 :- pragma foreign_proc("Java",
     open_3(DirName::in, _DirPattern::in, DirStream::out, Error::out,
-        _IO0::di, _IO::uo),
+        IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
     try {
@@ -1756,6 +1766,7 @@ open_2(DirName, DirPattern, Result, !IO) :-
         DirStream = null;
         Error = e;
     }
+    IsWin32Error = bool.NO;
 ").
 
 :- pred check_dir_readable(string::in, maybe_file_error::out,
@@ -1806,11 +1817,11 @@ check_dir_readable(DirName, Result, !IO) :-
     io::di, io::uo) is det.
 
 close(DirName, DirStream, Result, !IO) :-
-    close_2(DirStream, MaybeWin32Error, !IO),
+    close_2(DirStream, Error, IsWin32Error, !IO),
     % XXX The top level caller may not be dir.foldl2.
     % XXX The message is too verbose for use in a full file_error.
-    is_maybe_win32_error(MaybeWin32Error,
-        "closing directory failed: ", MaybeIOError, !IO),
+    is_error_maybe_win32(Error, IsWin32Error, "closing directory failed: ",
+        MaybeIOError, !IO),
     (
         MaybeIOError = yes(IOError),
         Result = mfe_error(file_error(DirName, file_close, IOError))
@@ -1819,11 +1830,11 @@ close(DirName, DirStream, Result, !IO) :-
         Result = mfe_ok(unit)
     ).
 
-:- pred close_2(dir.stream::in, io.system_error::out, io::di, io::uo)
-    is det.
+:- pred close_2(dir.stream::in, io.system_error::out, bool::out,
+    io::di, io::uo) is det.
 
 :- pragma foreign_proc("C",
-    close_2(DirStream::in, Error::out, _IO0::di, _IO::uo),
+    close_2(DirStream::in, Error::out, IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         will_not_modify_trail, does_not_affect_liveness, may_not_duplicate],
 "
@@ -1836,41 +1847,46 @@ close(DirName, DirStream, Result, !IO) :-
     } else {
         Error = GetLastError();
     }
+    IsWin32Error = MR_YES;
 #elif defined(MR_HAVE_CLOSEDIR)
     if (closedir(DirStream) == 0) {
         Error = 0;
     } else {
         Error = errno;
     }
+    IsWin32Error = MR_NO;
 #else
     Error = ENOSYS;
+    IsWin32Error = MR_NO;
 #endif
 ").
 
 :- pragma foreign_proc("C#",
-    close_2(_DirStream::in, Error::out, _IO0::di, _IO::uo),
+    close_2(_DirStream::in, Error::out, IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
     // Nothing to do.
     Error = null;
+    IsWin32Error = mr_bool.NO;
 ").
 
 :- pragma foreign_proc("Java",
-    close_2(_DirStream::in, Error::out, _IO0::di, _IO::uo),
+    close_2(_DirStream::in, Error::out, IsWin32Error::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
     // Nothing to do.
     Error = null;
+    IsWin32Error = bool.NO;
 ").
 
 :- pred read_entry(dir.stream::in, io.result(string)::out, io::di, io::uo)
     is det.
 
 read_entry(DirStream, Result, !IO) :-
-    read_entry_2(DirStream, MaybeWin32Error, HaveFileName, FileName, !IO),
+    read_entry_2(DirStream, Error, IsWin32Error, HaveFileName, FileName, !IO),
     % XXX The top level caller may not be dir.foldl2.
     % XXX The message is too verbose for use in a full file_error.
-    is_maybe_win32_error(MaybeWin32Error,
+    is_error_maybe_win32(Error, IsWin32Error,
         "reading directory entry failed: ", MaybeIOError, !IO),
     (
         MaybeIOError = yes(IOError),
@@ -1894,16 +1910,17 @@ read_entry(DirStream, Result, !IO) :-
         )
     ).
 
-    % read_entry_2(DirStream, MaybeWin32Error, HaveFileName, FileName, !IO):
+    % read_entry_2(DirStream, Error, IsWin32Error, HaveFileName, FileName,
+    %   !IO):
     % If there is no error and HaveFileName = no, then we have reached the
     % end-of-stream.
     %
 :- pred read_entry_2(dir.stream::in, io.system_error::out, bool::out,
-    string::out, io::di, io::uo) is det.
+    bool::out, string::out, io::di, io::uo) is det.
 
 :- pragma foreign_proc("C",
-    read_entry_2(DirStream::in, Error::out, HaveFileName::out, FileName::out,
-        _IO0::di, _IO::uo),
+    read_entry_2(DirStream::in, Error::out, IsWin32Error::out,
+        HaveFileName::out, FileName::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         will_not_modify_trail, does_not_affect_liveness, may_not_duplicate],
 "
@@ -1913,20 +1930,24 @@ read_entry(DirStream, Result, !IO) :-
     if (DirStream->handle == INVALID_HANDLE_VALUE) {
         // Directory was empty when opened.
         Error = 0;
+        IsWin32Error = MR_YES;
         HaveFileName = MR_NO;
         FileName = MR_make_string_const("""");
     } else if (DirStream->pending_entry != NULL) {
         // FindFirstFileW already returned the first entry.
         Error = 0;
+        IsWin32Error = MR_YES;
         HaveFileName = MR_YES;
         FileName = DirStream->pending_entry;
         DirStream->pending_entry = NULL;
     } else if (FindNextFileW(DirStream->handle, &file_data)) {
         Error = 0;
+        IsWin32Error = MR_YES;
         HaveFileName = MR_YES;
         FileName = ML_wide_to_utf8(file_data.cFileName, MR_ALLOC_ID);
     } else {
         Error = GetLastError();
+        IsWin32Error = MR_YES;
         if (Error == ERROR_NO_MORE_FILES) {
             Error = 0;
         }
@@ -1941,10 +1962,12 @@ read_entry(DirStream, Result, !IO) :-
     dir_entry = readdir(DirStream);
     if (dir_entry == NULL) {
         Error = errno;  // remains zero at end-of-stream
+        IsWin32Error = MR_NO;
         HaveFileName = MR_NO;
         FileName = MR_make_string_const("""");
     } else {
         Error = 0;
+        IsWin32Error = MR_NO;
         HaveFileName = MR_YES;
         MR_make_aligned_string_copy_msg(FileName, dir_entry->d_name,
             MR_ALLOC_ID);
@@ -1952,16 +1975,18 @@ read_entry(DirStream, Result, !IO) :-
 
 #else // !MR_WIN32 && !(MR_HAVE_READDIR etc.)
     Error = ENOSYS;
+    IsWin32Error = MR_NO;
     HaveFileName = MR_NO;
     FileName = MR_make_string_const("""");
 #endif
 ").
 
 :- pragma foreign_proc("C#",
-    read_entry_2(DirStream::in, Error::out, HaveFileName::out, FileName::out,
-        _IO0::di, _IO::uo),
+    read_entry_2(DirStream::in, Error::out, IsWin32Error::out,
+        HaveFileName::out, FileName::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
+
     try {
         if (DirStream.MoveNext()) {
             // The .NET CLI returns path names qualified with
@@ -1973,18 +1998,21 @@ read_entry(DirStream, Result, !IO) :-
             FileName = """";
         }
         Error = null;
+        IsWin32Error = mr_bool.NO;
     } catch (System.Exception e) {
         Error = e;
+        IsWin32Error = mr_bool.NO;
         HaveFileName = mr_bool.NO;
         FileName = """";
     }
 ").
 
 :- pragma foreign_proc("Java",
-    read_entry_2(DirStream::in, Error::out, HaveFileName::out, FileName::out,
-        _IO0::di, _IO::uo),
+    read_entry_2(DirStream::in, Error::out, IsWin32Error::out,
+        HaveFileName::out, FileName::out, _IO0::di, _IO::uo),
     [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
 "
+
     try {
         if (DirStream.hasNext()) {
             HaveFileName = bool.YES;
@@ -1994,8 +2022,10 @@ read_entry(DirStream, Result, !IO) :-
             FileName = """";
         }
         Error = null;
+        IsWin32Error = bool.NO;
     } catch (java.lang.Exception e) {
         Error = e;
+        IsWin32Error = bool.NO;
         HaveFileName = bool.NO;
         FileName = """";
     }
diff --git a/library/io.m b/library/io.m
index b9a8d91ef..70fdb5bcc 100644
--- a/library/io.m
+++ b/library/io.m
@@ -2067,6 +2067,28 @@
     %
 :- func make_io_error(string) = io.error.
 
+    % make_io_error_from_system_error(SystemError, Prefix, Error, !IO):
+    %
+    % Construct an io.error value given a system error and an error message
+    % prefix, which may be the empty string. The error message will be
+    % constructed by appending Prefix and the error message retrieved from the
+    % system for SystemError.
+    %
+    % On C backends, the io.system_error must be an errno value.
+    % On C# and Java backends, the io.system_error must be an exception object.
+    %
+:- pred make_io_error_from_system_error(io.system_error::in, string::in,
+    io.error::out, io::di, io::uo) is det.
+
+    % make_io_error_from_windows_error(SystemError, Prefix, Error, !IO):
+    %
+    % Construct an io.error value from the given Windows system error and error
+    % message prefix. This predicate may only be called when using a C backend
+    % running on Windows. On other platforms, it throws an exception.
+    %
+:- pred make_io_error_from_windows_error(io.system_error::in, string::in,
+    io.error::out, io::di, io::uo) is det.
+
     % Return an error message for the error value.
     %
 :- func error_message(io.error) = string.
@@ -2275,24 +2297,21 @@
 :- pred is_error(system_error::in, string::in, maybe(io.error)::out,
     io::di, io::uo) is det.
 
-    % is_maybe_win32_error(Error, MessagePrefix, MaybeIOError, !IO):
-    % Same as is_error except that Error is a Win32 error value on Windows.
+    % is_error_maybe_win32(Error, IsWin32Error, MessagePrefix, MaybeIOError,
+    %   !IO):
+    % Same as is_error except that IsWin32Error is `yes' if Error originates
+    % from a Win32 system error code, `no' otherwise.
     %
-:- pred is_maybe_win32_error(system_error::in, string::in,
+:- pred is_error_maybe_win32(system_error::in, bool::in, string::in,
     maybe(io.error)::out, io::di, io::uo) is det.
 
-    % Make an io.error from a system error and message prefix.
-    % On Windows, the system error is assumed to be a errno value.
+    % make_io_error_from_maybe_win32_error(Error, IsWin32Error, Prefix,
+    %   IOError, !IO):
+    % Helper to call either make_io_error_from_system_error or
+    % make_io_error_from_windows_error.
     %
-:- pred make_io_error_from_system_error(io.system_error::in, string::in,
-    io.error::out, io::di, io::uo) is det.
-
-    % Make an io.error from a system error and message prefix.
-    % On Windows, the system error is assumed to be a Windows system error
-    % code obtained by calling GetLastError().
-    %
-:- pred make_io_error_from_maybe_win32_error(io.system_error::in, string::in,
-    io.error::out, io::di, io::uo) is det.
+:- pred make_io_error_from_maybe_win32_error(system_error::in, bool::in,
+    string::in, io.error::out, io::di, io::uo) is det.
 
     % For use by bitmap.m, and other standard library modules
     % that want to do I/O.
@@ -4904,6 +4923,40 @@ report_tabling_statistics(!IO) :-
 
 make_io_error(Error) = io_error_string(Error).
 
+make_io_error_from_system_error(Error, Prefix, IOError, !IO) :-
+    SysErrStyle = native_system_error_style,
+    (
+        ( SysErrStyle = syserr_errno
+        ; SysErrStyle = syserr_errno_or_win32
+        ),
+        make_errno_message(Error, Prefix, Msg, !IO),
+        IOError = io_error_errno(Msg, Error)
+    ;
+        SysErrStyle = syserr_exception_object,
+        get_exception_object_message(Error, Msg0, !IO),
+        ( if Prefix = "" then
+            Msg = Msg0
+        else
+            Msg = Prefix ++ Msg0
+        ),
+        IOError = io_error_exception_object(Msg, Error)
+    ).
+
+make_io_error_from_windows_error(Error, Prefix, IOError, !IO) :-
+    SysErrStyle = native_system_error_style,
+    (
+        SysErrStyle = syserr_errno_or_win32,
+        make_win32_error_message(Error, Prefix, Msg, !IO),
+        IOError = io_error_win32(Msg, Error)
+    ;
+        ( SysErrStyle = syserr_errno
+        ; SysErrStyle = syserr_exception_object
+        ),
+        error("io.make_io_error_from_windows_error: inapplicable platform")
+    ).
+
+%---------------------%
+
 error_message(Error) = Msg :-
     error_message(Error, Msg).
 
@@ -5891,52 +5944,23 @@ is_error(Error, Prefix, MaybeError, !IO) :-
         MaybeError = yes(IOError)
     ).
 
-is_maybe_win32_error(Error, Prefix, MaybeError, !IO) :-
+is_error_maybe_win32(Error, IsWin32Error, Prefix, MaybeError, !IO) :-
     ( if is_success(Error) then
         MaybeError = no
     else
-        make_io_error_from_maybe_win32_error(Error, Prefix, IOError, !IO),
+        make_io_error_from_maybe_win32_error(Error, IsWin32Error, Prefix,
+            IOError, !IO),
         MaybeError = yes(IOError)
     ).
 
-make_io_error_from_system_error(Error, Prefix, IOError, !IO) :-
-    SysErrStyle = native_system_error_style,
+make_io_error_from_maybe_win32_error(Error, IsWin32Error, Prefix, IOError,
+        !IO) :-
     (
-        ( SysErrStyle = syserr_errno
-        ; SysErrStyle = syserr_errno_or_win32
-        ),
-        make_errno_message(Error, Prefix, Msg, !IO),
-        IOError = io_error_errno(Msg, Error)
+        IsWin32Error = yes,
+        make_io_error_from_windows_error(Error, Prefix, IOError, !IO)
     ;
-        SysErrStyle = syserr_exception_object,
-        get_exception_object_message(Error, Msg0, !IO),
-        ( if Prefix = "" then
-            Msg = Msg0
-        else
-            Msg = Prefix ++ Msg0
-        ),
-        IOError = io_error_exception_object(Msg, Error)
-    ).
-
-make_io_error_from_maybe_win32_error(Error, Prefix, IOError, !IO) :-
-    SysErrStyle = native_system_error_style,
-    (
-        SysErrStyle = syserr_errno,
-        make_errno_message(Error, Prefix, Msg, !IO),
-        IOError = io_error_errno(Msg, Error)
-    ;
-        SysErrStyle = syserr_errno_or_win32,
-        make_win32_error_message(Error, Prefix, Msg, !IO),
-        IOError = io_error_win32(Msg, Error)
-    ;
-        SysErrStyle = syserr_exception_object,
-        get_exception_object_message(Error, Msg0, !IO),
-        ( if Prefix = "" then
-            Msg = Msg0
-        else
-            Msg = Prefix ++ Msg0
-        ),
-        IOError = io_error_exception_object(Msg, Error)
+        IsWin32Error = no,
+        make_io_error_from_system_error(Error, Prefix, IOError, !IO)
     ).
 
 :- pred throw_on_error(system_error::in, string::in, io::di, io::uo) is det.
-- 
2.37.1



More information about the reviews mailing list