[m-rev.] for review: io.make_temp now reterns a result rather than throw exceptions

Paul Bone paul at bone.id.au
Wed Apr 20 14:00:52 AEST 2016


On Wed, Apr 20, 2016 at 01:22:42PM +1000, Peter Wang wrote:
> On Wed, 20 Apr 2016 12:44:38 +1000, Paul Bone <paul at bone.id.au> wrote:
> > For review by Peter Wang who suggested this change.
> 
> Hi Paul,
> 
> Can you resend with diff -w?  Some parts are hard to follow.

Okay, I reflowed some things, especially comments, as indentation levels
changed, so they'll still be part of the diff.

>From 6f03058105c31e75fdcb88e010ea50b427f304bd Mon Sep 17 00:00:00 2001
From: Paul Bone <paul at bone.id.au>
Date: Wed, 20 Apr 2016 12:23:23 +1000
Subject: [PATCH] io.make_temp now reterns a result rather than throw
 exceptions

The make_temp predicates would throw an exception if they were unsuccessful,
New versions of make_temp/3 and make_temp/5 have been created (named
make_temp_res) to avoid braking code.  make_temp/3 and make_temp/5 have been
marked as obsolete.  make_temp_directory/3 and make_temp_directory/5 have
been modified directly as they are very new.  This closes bug #408

Some routines in compiler/compile_target_code.m used the name returned by
make_temp and added a suffix before using the resulting file, this sould
create unnecessary temporary files that I beleive were never cleaned up.  So
I've added a suffix argument to make_temp_res/5 and make_temp_directory/5
(now they're make_temp_res/6 and make_temp_directory/6).

library/io.m:
    As above.

    Remove out-of-date comment.

compiler/compile_target_code.m:
    Conform to changes in io.m.

    Use the new suffix argument to reduce the number of temporary files
    created during linking.

compiler/fact_table.m:
compiler/make.module_target.m:
compiler/make.util.m:
compiler/module_cmds.m:
compiler/prog_event.m:
compiler/write_deps_file.m:
deep_profiler/conf.m:
    Conform to changes in io.m.
---
 compiler/compile_target_code.m |  60 ++++++++++---
 compiler/fact_table.m          |  31 +++++--
 compiler/make.module_target.m  |  32 +++++--
 compiler/make.util.m           |  16 +++-
 compiler/module_cmds.m         |  30 +++++--
 compiler/prog_event.m          |  28 ++++--
 compiler/write_deps_file.m     | 189 ++++++++++++++++++++++------------------
 deep_profiler/conf.m           |  13 ++-
 library/io.m                   | 190 +++++++++++++++++++++++------------------
 9 files changed, 385 insertions(+), 204 deletions(-)

diff --git a/compiler/compile_target_code.m b/compiler/compile_target_code.m
index 48453b4..ce11561 100644
--- a/compiler/compile_target_code.m
+++ b/compiler/compile_target_code.m
@@ -1254,7 +1254,9 @@ invoke_mkinit(Globals, InitFileStream, Verbosity,
     % mkinit expects unquoted file names.
     join_string_list(FileNames, "", "\n", "", TargetFileNames),
 
-    io.make_temp(TmpFile, !IO),
+    io.make_temp_res(TmpFileResult, !IO),
+    (
+        TmpFileResult = ok(TmpFile),
         io.open_output(TmpFile, OpenResult, !IO),
         (
             OpenResult = ok(TmpStream),
@@ -1274,7 +1276,15 @@ invoke_mkinit(Globals, InitFileStream, Verbosity,
                 MkInitOK = no
             )
         ;
-        OpenResult = error(_),
+            OpenResult = error(Error),
+            io.format(io.stderr_stream, "%s: %s\n",
+                [s(TmpFile), s(error_message(Error))], !IO),
+            MkInitOK = no
+        )
+    ;
+        TmpFileResult = error(Error),
+        io.format(io.stderr_stream, "Could not create temporary file: %s\n",
+            [s(error_message(Error))], !IO),
         MkInitOK = no
     ).
 
@@ -1977,8 +1987,12 @@ link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType, ModuleName,
             % and thus overflow the command line, so in this case
             % we first create an archive of all of the object files.
             RestrictedCommandLine = yes,
-            io.make_temp(TmpFile, !IO),
             globals.lookup_string_option(Globals, library_extension, LibExt),
+            io.get_temp_directory(TempDir, !IO),
+            io.make_temp_res(TempDir, "", "." ++ LibExt, TmpFileResult, !IO),
+            (
+                TmpFileResult = ok(TmpFile),
+                % XXX: This is why my /tmp directory is always full of crap.
                 TmpArchive = TmpFile ++ LibExt,
                 % Only include actual object files in the temporary archive,
                 % not other files such as other archives.
@@ -1990,6 +2004,15 @@ link_exe_or_shared_lib(Globals, ErrorStream, LinkTargetType, ModuleName,
                 join_quoted_string_list([TmpArchive | NonObjectFiles],
                     "", "", " ", Objects)
             ;
+                TmpFileResult = error(Error),
+                io.format(stderr_stream,
+                    "Could not create temporary file: %s\n",
+                    [s(error_message(Error))], !IO),
+                ArchiveSucceeded = no,
+                MaybeDeleteTmpArchive = no,
+                join_quoted_string_list(ObjectsList, "", "", " ", Objects)
+            )
+        ;
             RestrictedCommandLine = no,
             ArchiveSucceeded = yes,
             MaybeDeleteTmpArchive = no,
@@ -3043,7 +3066,9 @@ create_java_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
     % extremely long. We create the temporary file in the current directory to
     % avoid problems under Cygwin, where absolute paths will be interpreted
     % incorrectly when passed to a non-Cygwin jar program.
-    io.make_temp(".", "mtmp", TempFileName, !IO),
+    io.make_temp_res(".", "mtmp", "", TempFileNameResult, !IO),
+    (
+        TempFileNameResult = ok(TempFileName),
         io.open_output(TempFileName, OpenResult, !IO),
         (
             OpenResult = ok(Stream),
@@ -3053,8 +3078,8 @@ create_java_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
 
             Cmd = string.append_list(
                 [Jar, " cf ", JarFileName, " @", TempFileName]),
-        invoke_system_command(Globals, ErrorStream, cmd_verbose_commands, Cmd,
-            Succeeded0, !IO),
+            invoke_system_command(Globals, ErrorStream,
+                cmd_verbose_commands, Cmd, Succeeded0, !IO),
             io.remove_file(TempFileName, _, !IO),
             (
                 Succeeded0 = yes
@@ -3064,9 +3089,14 @@ create_java_exe_or_lib(Globals, ErrorStream, LinkTargetType, MainModuleName,
             )
         ;
             OpenResult = error(Error),
-        io.error_message(Error, ErrorMsg),
             io.format(ErrorStream, "Error creating `%s': %s\n",
-            [s(TempFileName), s(ErrorMsg)], !IO),
+                [s(TempFileName), s(error_message(Error))], !IO),
+            Succeeded0 = no
+        )
+    ;
+        TempFileNameResult = error(Error),
+        io.format(ErrorStream, "Could not create temporary file: %s\n",
+            [s(error_message(Error))], !IO),
         Succeeded0 = no
     ),
     ( if
@@ -3463,7 +3493,9 @@ invoke_long_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
         RestrictedCommandLine = yes,
 
         % Avoid generating very long command lines by using @files.
-        io.make_temp(TmpFile, !IO),
+        io.make_temp_res(TmpFileResult, !IO),
+        (
+            TmpFileResult = ok(TmpFile),
             io.open_output(TmpFile, OpenResult, !IO),
             (
                 OpenResult = ok(TmpStream),
@@ -3504,7 +3536,15 @@ invoke_long_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
                     Succeeded = no
                 )
             ;
-            OpenResult = error(_),
+                OpenResult = error(Error),
+                io.format(stderr_stream, "%s: %s\n",
+                    [s(TmpFile), s(error_message(Error))], !IO),
+                Succeeded = no
+            )
+        ;
+            TmpFileResult = error(Error),
+            io.format(stderr_stream, "Could not create temporary file: %s\n",
+                [s(error_message(Error))], !IO),
             Succeeded = no
         )
     ;
diff --git a/compiler/fact_table.m b/compiler/fact_table.m
index cf01d59..7b4559a 100644
--- a/compiler/fact_table.m
+++ b/compiler/fact_table.m
@@ -309,16 +309,28 @@ fact_table_compile_facts_2(PredName, Arity, FileName, !PredInfo, Context,
             infer_determinism_pass_2(ProcFiles, Globals, ExistsAllInMode,
                 ProcTable0, ProcTable, !IO),
             pred_info_set_proc_table(ProcTable, !PredInfo),
-            io.make_temp(DataFileName, !IO),
+            io.make_temp_res(DataFileNameResult, !IO),
+            (
+                DataFileNameResult = ok(DataFileName),
                 write_fact_table_arrays(ProcFiles, DataFileName, StructName,
-                ProcTable, ModuleInfo, NumFacts, FactArgInfos, WriteHashTables,
-                WriteDataAfterSorting, OutputStream, C_HeaderCode1,
-                PrimaryProcID, !IO),
+                    ProcTable, ModuleInfo, NumFacts, FactArgInfos,
+                    WriteHashTables, WriteDataAfterSorting, OutputStream,
+                    C_HeaderCode1, PrimaryProcID, !IO),
                 write_fact_table_numfacts(PredName, NumFacts, OutputStream,
                     C_HeaderCode3, !IO),
                 string.append_list([C_HeaderCode0, C_HeaderCode1,
                     C_HeaderCode2, C_HeaderCode3], C_HeaderCode)
             ;
+                DataFileNameResult = error(Error),
+                ErrorReport = no - [
+                    words("Could not create temporary file:"),
+                    quote(error_message(Error))],
+                print_error_reports(Globals, [ErrorReport], !IO),
+                C_HeaderCode = C_HeaderCode0,
+                PrimaryProcID = invalid_proc_id,
+                DataFileName = ""
+            )
+        ;
             OpenCompileErrors = [_ | _],
             print_error_reports(Globals, OpenCompileErrors, !IO),
             C_HeaderCode = C_HeaderCode0,
@@ -967,7 +979,9 @@ fact_table_mode_type([Mode | Modes], ModuleInfo, ModeType) :-
 
 open_sort_files([], [], !Errors, !IO).
 open_sort_files([ProcID | ProcIDs], ProcStreams, !Errors, !IO) :-
-    io.make_temp(SortFileName, !IO),
+    io.make_temp_res(SortFileNameResult, !IO),
+    (
+        SortFileNameResult = ok(SortFileName),
         io.open_output(SortFileName, Result, !IO),
         (
             Result = ok(Stream),
@@ -980,6 +994,13 @@ open_sort_files([ProcID | ProcIDs], ProcStreams, !Errors, !IO) :-
             string.format("Error opening file `%s' for output: %s.",
                 [s(SortFileName), s(Message)], Msg),
             add_error_report([words(Msg)], !Errors)
+        )
+    ;
+        SortFileNameResult = error(Error),
+        ProcStreams = [],
+        string.format("Could not create temporary file: %s.",
+            [s(error_message(Error))], Msg),
+        add_error_report([words(Msg)], !Errors)
     ).
 
     % close_sort_files(ProcStreams, ProcFiles, !IO):
diff --git a/compiler/make.module_target.m b/compiler/make.module_target.m
index 6d1f22f..0a9d037 100644
--- a/compiler/make.module_target.m
+++ b/compiler/make.module_target.m
@@ -362,18 +362,30 @@ build_target(Globals, CompilationTask, TargetFile, Imports, TouchedTargetFiles,
         % We need a temporary file to pass the arguments to the mmc process
         % which will do the compilation. It is created here (not in invoke_mmc)
         % so it can be cleaned up by build_with_check_for_interrupt.
-        io.make_temp(ArgFileName, !IO),
-        MaybeArgFileName = yes(ArgFileName)
+        io.make_temp_res(ArgFileNameResult, !IO),
+        (
+            ArgFileNameResult = ok(ArgFileName),
+            MaybeArgFileName = yes(ArgFileName),
+            ArgFileNameSuccess = ok `with_type` io.res
+        ;
+            ArgFileNameResult = error(Error),
+            MaybeArgFileName = no,
+            ArgFileNameSuccess = error(Error)
+        )
     else
-        MaybeArgFileName = no
+        MaybeArgFileName = no,
+        ArgFileNameSuccess = ok
     ),
-    Cleanup =
-        ( pred(!.MakeInfo::in, !:MakeInfo::out, !.IO::di, !:IO::uo) is det :-
+
+    (
+        ArgFileNameSuccess = ok,
+        Cleanup = (pred(!.MakeInfo::in, !:MakeInfo::out, !.IO::di, !:IO::uo)
+                    is det :-
                 % XXX Remove `.int.tmp' files.
                 list.foldl2(make_remove_target_file(Globals, very_verbose),
                     TouchedTargetFiles, !MakeInfo, !IO),
-            list.foldl2(make_remove_file(Globals, very_verbose), TouchedFiles,
-                !MakeInfo, !IO),
+                list.foldl2(make_remove_file(Globals, very_verbose),
+                    TouchedFiles, !MakeInfo, !IO),
                 (
                     MaybeArgFileName = yes(ArgFileName2),
                     io.remove_file(ArgFileName2, _, !IO)
@@ -407,6 +419,12 @@ build_target(Globals, CompilationTask, TargetFile, Imports, TouchedTargetFiles,
             )
         ;
             ShowMakeTimes = no
+        )
+    ;
+        ArgFileNameSuccess = error(ArgFileError),
+        io.format(stderr_stream, "Could not create temporary file: %s\n",
+            [s(error_message(ArgFileError))], !IO),
+        Succeeded = no
     ).
 
 :- pred build_target_2(module_name::in, compilation_task_type::in,
diff --git a/compiler/make.util.m b/compiler/make.util.m
index 4b2abc1..7488416 100644
--- a/compiler/make.util.m
+++ b/compiler/make.util.m
@@ -1074,7 +1074,9 @@ redirect_output(_ModuleName, MaybeErrorStream, !Info, !IO) :-
     % the part of the error file that relates to the current command. It will
     % be appended to the error file later.
 
-    io.make_temp(ErrorFileName, !IO),
+    io.make_temp_res(ErrorFileNameResult, !IO),
+    (
+        ErrorFileNameResult = ok(ErrorFileName),
         io.open_output(ErrorFileName, ErrorFileRes, !IO),
         (
             ErrorFileRes = ok(ErrorOutputStream),
@@ -1084,6 +1086,12 @@ redirect_output(_ModuleName, MaybeErrorStream, !Info, !IO) :-
             MaybeErrorStream = no,
             with_locked_stdout(!.Info,
                 write_error_opening_output(ErrorFileName, IOError), !IO)
+        )
+    ;
+        ErrorFileNameResult = error(IOError),
+        MaybeErrorStream = no,
+        with_locked_stdout(!.Info, write_error_creating_temp_file(IOError),
+            !IO)
     ).
 
 unredirect_output(Globals, ModuleName, ErrorOutputStream, !Info, !IO) :-
@@ -1182,6 +1190,12 @@ write_error_opening_file(FileName, Error, !IO) :-
     io.format("Error opening `%s': %s\n",
         [s(FileName), s(io.error_message(Error))], !IO).
 
+:- pred write_error_creating_temp_file(io.error::in, io::di, io::uo) is det.
+
+write_error_creating_temp_file(Error, !IO) :-
+    io.format("Error creating temporary file: %s\n",
+        [s(io.error_message(Error))], !IO).
+
 %-----------------------------------------------------------------------------%
 
 get_timestamp_file_timestamp(Globals, target_file(ModuleName, FileType),
diff --git a/compiler/module_cmds.m b/compiler/module_cmds.m
index 2e56455..b54a199 100644
--- a/compiler/module_cmds.m
+++ b/compiler/module_cmds.m
@@ -575,7 +575,9 @@ invoke_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
     % the output from the command would go to the current C output
     % and error streams.
 
-    io.make_temp(TmpFile, !IO),
+    io.make_temp_res(TmpFileResult, !IO),
+    (
+        TmpFileResult = ok(TmpFile),
         ( if use_dotnet then
             % XXX can't use Bourne shell syntax to redirect on .NET
             % XXX the output will go to the wrong place!
@@ -600,7 +602,8 @@ invoke_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
             )
         ;
             Result = ok(signalled(Signal)),
-        report_error_to_stream(ErrorStream, "system command received signal "
+            report_error_to_stream(ErrorStream,
+                "system command received signal "
                 ++ int_to_string(Signal) ++ ".", !IO),
             % Also report the error to standard output, because if we raise the
             % signal this error may not ever been seen, the process stops and
@@ -616,6 +619,13 @@ invoke_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
             Result = error(Error),
             report_error_to_stream(ErrorStream, io.error_message(Error), !IO),
             CommandSucceeded = no
+        )
+    ;
+        TmpFileResult = error(Error),
+        report_error_to_stream(ErrorStream,
+            "Could not create temporary file: " ++ error_message(Error), !IO),
+        TmpFile = "",
+        CommandSucceeded = no
     ),
 
     ( if
@@ -623,7 +633,9 @@ invoke_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
         not use_dotnet,
         MaybeProcessOutput = yes(ProcessOutput)
     then
-        io.make_temp(ProcessedTmpFile, !IO),
+        io.make_temp_res(ProcessedTmpFileResult, !IO),
+        (
+            ProcessedTmpFileResult = ok(ProcessedTmpFile),
 
             % XXX we should get rid of use_win32
             ( if use_win32 then
@@ -659,8 +671,9 @@ invoke_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
                 )
             ;
                 ProcessOutputResult = ok(signalled(ProcessOutputSignal)),
-            % Make sure the current process gets the signal. Some systems
-            % (e.g. Linux) ignore SIGINT during a call to system().
+                % Make sure the current process gets the signal. Some
+                % systems (e.g. Linux) ignore SIGINT during a call to
+                % system().
                 raise_signal(ProcessOutputSignal, !IO),
                 report_error_to_stream(ErrorStream,
                     "system command received signal "
@@ -672,6 +685,13 @@ invoke_system_command_maybe_filter_output(Globals, ErrorStream, Verbosity,
                     io.error_message(ProcessOutputError), !IO),
                 ProcessOutputSucceeded = no
             )
+        ;
+            ProcessedTmpFileResult = error(ProcessTmpError),
+            report_error_to_stream(ErrorStream,
+                io.error_message(ProcessTmpError), !IO),
+            ProcessOutputSucceeded = no,
+            ProcessedTmpFile = ""
+        )
     else
         ProcessOutputSucceeded = yes,
         ProcessedTmpFile = TmpFile
diff --git a/compiler/prog_event.m b/compiler/prog_event.m
index 65a72c0..717c06c 100644
--- a/compiler/prog_event.m
+++ b/compiler/prog_event.m
@@ -92,7 +92,9 @@ read_event_set(SpecsFileName, EventSetName, EventSpecMap, ErrorSpecs, !IO) :-
     % those tools are not yet mature enough. When they are, we should switch
     % to using them.
 
-    io.make_temp(TermFileName, !IO),
+    io.make_temp_res(TermFileNameResult, !IO),
+    (
+        TermFileNameResult = ok(TermFileName),
         read_specs_file(SpecsFileName, TermFileName, Problem, !IO),
         ( if Problem = "" then
             io.open_input(TermFileName, TermOpenRes, !IO),
@@ -101,7 +103,8 @@ read_event_set(SpecsFileName, EventSetName, EventSpecMap, ErrorSpecs, !IO) :-
                 io.read(TermStream, TermReadRes, !IO),
                 (
                     TermReadRes = ok(EventSetTerm),
-                EventSetTerm = event_set_spec(EventSetName, EventSpecsTerm),
+                    EventSetTerm = event_set_spec(EventSetName,
+                        EventSpecsTerm),
                     convert_list_to_spec_map(SpecsFileName, EventSpecsTerm,
                         map.init, EventSpecMap, [], ErrorSpecs)
                 ;
@@ -130,9 +133,12 @@ read_event_set(SpecsFileName, EventSetName, EventSpecMap, ErrorSpecs, !IO) :-
                 TermOpenRes = error(TermOpenError),
                 EventSetName = "",
                 EventSpecMap = map.init,
-            Pieces = [words(io.error_message(TermOpenError)), nl],
-            ErrorSpec = error_spec(severity_error, phase_term_to_parse_tree,
-                [error_msg(no, do_not_treat_as_first, 0, [always(Pieces)])]),
+                Pieces = [words("Could not open"), quote(TermFileName),
+                    words(":"), words_quote(error_message(TermOpenError)), nl],
+                ErrorSpec = error_spec(severity_error,
+                    phase_term_to_parse_tree,
+                    [error_msg(no, do_not_treat_as_first, 0,
+                        [always(Pieces)])]),
                 ErrorSpecs = [ErrorSpec]
             )
         else
@@ -143,7 +149,17 @@ read_event_set(SpecsFileName, EventSetName, EventSpecMap, ErrorSpecs, !IO) :-
                 [error_msg(no, do_not_treat_as_first, 0, [always(Pieces)])]),
             ErrorSpecs = [ErrorSpec]
         ),
-    io.remove_file(TermFileName, _RemoveRes, !IO).
+        io.remove_file(TermFileName, _RemoveRes, !IO)
+    ;
+        TermFileNameResult= error(TermFileNameError),
+        EventSetName = "",
+        EventSpecMap = map.init,
+        Pieces = [words("Could not create temporary file:"),
+            words_quote(error_message(TermFileNameError)), nl],
+        ErrorSpec = error_spec(severity_error, phase_term_to_parse_tree,
+            [error_msg(no, do_not_treat_as_first, 0, [always(Pieces)])]),
+        ErrorSpecs = [ErrorSpec]
+    ).
 
 :- pred read_specs_file(string::in, string::in, string::out,
     io::di, io::uo) is det.
diff --git a/compiler/write_deps_file.m b/compiler/write_deps_file.m
index e661e06..caac87b 100644
--- a/compiler/write_deps_file.m
+++ b/compiler/write_deps_file.m
@@ -159,8 +159,14 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
     % parallel makes, we first create the file with a temporary name,
     % and then rename it to the desired name when we've finished.
 
-    io.make_temp(dir.dirname(DependencyFileName), "tmp_d",
-        TmpDependencyFileName, !IO),
+    io.make_temp_res(dir.dirname(DependencyFileName), "tmp_d",
+        "", TmpDependencyFileNameRes, !IO),
+    (
+        TmpDependencyFileNameRes = error(Error),
+        Message = "Could not create temporary file: " ++ error_message(Error),
+        report_error(Message, !IO)
+    ;
+        TmpDependencyFileNameRes = ok(TmpDependencyFileName),
         maybe_write_string(Verbose, "% Writing auto-dependency file `", !IO),
         maybe_write_string(Verbose, DependencyFileName, !IO),
         maybe_write_string(Verbose, "'...", !IO),
@@ -244,8 +250,9 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 do_not_create_dirs, ObjFileName, !IO),
             module_name_to_file_name(Globals, ModuleName, ".java_date",
                 do_not_create_dirs, JavaDateFileName, !IO),
-        % XXX Why is the extension hardcoded to .pic_o here?  That looks wrong.
-        % It should probably be .$(EXT_FOR_PIC_OBJECT) - juliensf.
+            % XXX Why is the extension hardcoded to .pic_o here?  That looks
+            % wrong.  It should probably be .$(EXT_FOR_PIC_OBJECT) -
+            % juliensf.
             module_name_to_file_name(Globals, ModuleName, ".pic_o",
                 do_not_create_dirs, PicObjFileName, !IO),
             module_name_to_file_name(Globals, ModuleName, ".int0",
@@ -292,8 +299,9 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
             ),
 
             ForeignIncludeFiles = cord.list(ForeignIncludeFilesCord),
-        % This is conservative: a target file for foreign language A does not
-        % does not truly depend on a file included for foreign language B.
+            % This is conservative: a target file for foreign language A
+            % does not does not truly depend on a file included for foreign
+            % language B.
             write_foreign_include_file_dependencies_list(DepStream,
                 SourceFileName, ForeignIncludeFiles, !IO),
 
@@ -383,7 +391,8 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 else
                     bool.not(UseOptFiles, BuildOptFiles),
                     get_opt_deps(Globals, BuildOptFiles, IntermodDirs, ".opt",
-                    [ModuleName | set.to_sorted_list(LongDeps)], OptDeps, !IO),
+                        [ModuleName | set.to_sorted_list(LongDeps)],
+                        OptDeps, !IO),
                     OptInt0Deps = set.union_list(
                         list.map(get_ancestors_set, OptDeps)),
                     write_dependencies_list(Globals, DepStream, ".opt",
@@ -401,10 +410,10 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 HighLevelCode = yes,
                 CompilationTarget = target_c
             then
-            % For --high-level-code with --target c, we need to make sure that
-            % we generate the header files for imported modules before
-            % compiling the C files, since the generated C files
-            % #include those header files.
+                % For --high-level-code with --target c, we need to make
+                % sure that we generate the header files for imported
+                % modules before compiling the C files, since the generated
+                % C files #include those header files.
 
                 io.write_strings(DepStream, [
                     "\n\n",
@@ -416,14 +425,15 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 true
             ),
 
-        % We need to tell make how to make the header files. The header files
-        % are actually built by the same command that creates the .c or .s
-        % file, so we just make them depend on the .c or .s files.
-        % This is needed for the --high-level-code rule above, and for
-        % the rules introduced for `:- pragma foreign_import_module'
-        % declarations. In some grades the header file won't actually be built
-        % (e.g. LLDS grades for modules not containing `:- pragma export'
-        % declarations), but this rule won't do any harm.
+            % We need to tell make how to make the header files. The header
+            % files are actually built by the same command that creates the
+            % .c or .s file, so we just make them depend on the .c or .s
+            % files.  This is needed for the --high-level-code rule above,
+            % and for the rules introduced for `:- pragma
+            % foreign_import_module' declarations. In some grades the header
+            % file won't actually be built (e.g. LLDS grades for modules not
+            % containing `:- pragma export' declarations), but this rule
+            % won't do any harm.
 
             module_name_to_file_name(Globals, ModuleName, ".c",
                 do_not_create_dirs, CFileName, !IO),
@@ -453,18 +463,18 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 "endif\n"
             ], !IO),
 
-        % The .date and .date0 files depend on the .int0 files for the parent
-        % modules, and the .int3 files for the directly and indirectly imported
-        % modules.
+            % The .date and .date0 files depend on the .int0 files for the
+            % parent modules, and the .int3 files for the directly and
+            % indirectly imported modules.
             %
-        % For nested sub-modules, the `.date' files for the parent modules
-        % also depend on the same things as the `.date' files for this module,
-        % since all the `.date' files will get produced by a single mmc
-        % command. Similarly for `.date0' files, except these don't depend
-        % on the `.int0' files, because when doing the
-        % `--make-private-interface' for nested modules, mmc will process
-        % the modules in outermost to innermost order so as to produce each
-        % `.int0' file before it is needed.
+            % For nested sub-modules, the `.date' files for the parent
+            % modules also depend on the same things as the `.date' files
+            % for this module, since all the `.date' files will get produced
+            % by a single mmc command. Similarly for `.date0' files, except
+            % these don't depend on the `.int0' files, because when doing
+            % the `--make-private-interface' for nested modules, mmc will
+            % process the modules in outermost to innermost order so as to
+            % produce each `.int0' file before it is needed.
 
             module_name_to_file_name(Globals, ModuleName, ".date",
                 do_not_create_dirs, DateFileName, !IO),
@@ -473,22 +483,26 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
             io.write_strings(DepStream, [
                 "\n\n", DateFileName, " ", Date0FileName
             ], !IO),
-        write_dependencies_set(Globals, DepStream, ".date", ParentDeps, !IO),
+            write_dependencies_set(Globals, DepStream, ".date", ParentDeps,
+                !IO),
             io.write_strings(DepStream, [" : ", SourceFileName], !IO),
-        write_dependencies_set(Globals, DepStream, ".int0", ParentDeps, !IO),
+            write_dependencies_set(Globals, DepStream, ".int0", ParentDeps,
+                !IO),
             write_dependencies_set(Globals, DepStream, ".int3", LongDeps, !IO),
-        write_dependencies_set(Globals, DepStream, ".int3", ShortDeps, !IO),
+            write_dependencies_set(Globals, DepStream, ".int3", ShortDeps,
+                !IO),
 
             io.write_strings(DepStream, ["\n\n", Date0FileName], !IO),
-        write_dependencies_set(Globals, DepStream, ".date0", ParentDeps, !IO),
+            write_dependencies_set(Globals, DepStream, ".date0", ParentDeps,
+                !IO),
             io.write_strings(DepStream, [" : ", SourceFileName], !IO),
             write_dependencies_set(Globals, DepStream, ".int3", LongDeps, !IO),
             write_dependencies_set(Globals, DepStream, ".int3", ShortDeps, !IO),
             io.write_string(DepStream, "\n\n", !IO),
 
-        % If we can pass the module name rather than the file name, then do so.
-        % `--smart-recompilation' doesn't work if the file name is passed
-        % and the module name doesn't match the file name.
+            % If we can pass the module name rather than the file name, then
+            % do so.  `--smart-recompilation' doesn't work if the file name
+            % is passed and the module name doesn't match the file name.
 
             have_source_file_map(HaveMap, !IO),
             (
@@ -526,11 +540,11 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 get_foreign_code_indicators_from_item_blocks(Globals,
                     cord.list(IntForOptItemBlocksCord),
                     _IntForOptLangSet, IntForOptForeignImportModules, _, _),
-            % If we are generating the `.dep' file, ForeignImportModuless0
-            % will contain a conservative approximation to the set of
-            % foreign imports needed which will include imports
-            % required by imported modules.
-            % XXX ITEM_LIST What is the correctness argument that supports
+                % If we are generating the `.dep' file,
+                % ForeignImportModuless0 will contain a conservative
+                % approximation to the set of foreign imports needed which
+                % will include imports required by imported modules.  XXX
+                % ITEM_LIST What is the correctness argument that supports
                 % the above assertion?
                 ( if
                     ForeignImportModules0 = foreign_import_modules(
@@ -574,12 +588,13 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
             % `:- pragma foreign_import_module' declarations.
 
             set.filter_map(
-            ( pred(ForeignImportMod::in, ImportModuleName::out) is semidet :-
+                ( pred(ForeignImportMod::in, ImportModuleName::out)
+                        is semidet :-
                     ImportModuleName = foreign_import_module_name_from_module(
                         ForeignImportMod, SourceFileModuleName),
 
-                % XXX We can't include mercury.dll as mmake can't find it,
-                % but we know that it exists.
+                    % XXX We can't include mercury.dll as mmake can't find
+                    % it, but we know that it exists.
                     ImportModuleName \= unqualified("mercury")
                 ), ForeignImports, ForeignImportedModuleNames),
             ( if set.is_empty(ForeignImportedModuleNames) then
@@ -600,24 +615,27 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                     ForeignImportExt = ".hrl"
                 ;
                     Target = target_c,
-                % NOTE: for C the possible targets might be a .o file _or_ a
-                % .pic_o file. We need to include dependencies for the latter
-                % otherwise invoking mmake with a <module>.pic_o target will
-                % break.
+                    % NOTE: for C the possible targets might be a .o file
+                    % _or_ a .pic_o file. We need to include dependencies
+                    % for the latter otherwise invoking mmake with a
+                    % <module>.pic_o target will break.
                     ForeignImportTargets = [ObjFileName, PicObjFileName],
                     ForeignImportExt = ".mh"
                 ),
                 WriteForeignImportTarget =
-                ( pred(ForeignImportTarget::in, !.IO::di, !:IO::uo) is det :-
+                    ( pred(ForeignImportTarget::in, !.IO::di, !:IO::uo)
+                            is det :-
                         io.write_string(DepStream, "\n\n", !IO),
                         io.write_string(DepStream, ForeignImportTarget, !IO),
                         io.write_string(DepStream, " : ", !IO),
                         write_dependencies_list(Globals, DepStream,
                             ForeignImportExt,
-                        set.to_sorted_list(ForeignImportedModuleNames), !IO),
+                            set.to_sorted_list(ForeignImportedModuleNames),
+                            !IO),
                         io.write_string(DepStream, "\n\n", !IO)
                     ),
-            list.foldl(WriteForeignImportTarget, ForeignImportTargets, !IO)
+                list.foldl(WriteForeignImportTarget, ForeignImportTargets,
+                    !IO)
             ),
 
             module_name_to_file_name(Globals, ModuleName, ".int",
@@ -633,21 +651,21 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
             module_name_to_file_name(Globals, ModuleName, ".date3",
                 do_not_create_dirs, Date3FileName, !IO),
 
-        % We add some extra dependencies to the generated `.d' files, so that
-        % local `.int', `.opt', etc. files shadow the installed versions
-        % properly (e.g. for when you're trying to build a new version
-        % of an installed library). This saves the user from having to add
-        % these explicitly if they have multiple libraries installed
-        % in the same installation hierarchy which aren't independent (e.g.
-        % one uses another). These extra dependencies are necessary due to
-        % the way the combination of search paths and pattern rules
-        % works in Make.
+            % We add some extra dependencies to the generated `.d' files, so
+            % that local `.int', `.opt', etc. files shadow the installed
+            % versions properly (e.g. for when you're trying to build a new
+            % version of an installed library). This saves the user from
+            % having to add these explicitly if they have multiple libraries
+            % installed in the same installation hierarchy which aren't
+            % independent (e.g.  one uses another). These extra dependencies
+            % are necessary due to the way the combination of search paths
+            % and pattern rules works in Make.
             %
-        % Be very careful about changing the following rules. The `@:' is a
-        % silent do-nothing command. It is used to force GNU Make to recheck
-        % the timestamp on the target file. (It is a pity that GNU Make
-        % doesn't have a way of handling these sorts of rules in a
-        % nicer manner.)
+            % Be very careful about changing the following rules. The `@:'
+            % is a silent do-nothing command. It is used to force GNU Make
+            % to recheck the timestamp on the target file. (It is a pity
+            % that GNU Make doesn't have a way of handling these sorts of
+            % rules in a nicer manner.)
 
             io.write_strings(DepStream, [
                 "\n",
@@ -670,7 +688,8 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 UseSubdirs = yes,
                 io.nl(DepStream, !IO),
                 list.foldl(
-                write_subdirs_shorthand_rule(Globals, DepStream, ModuleName),
+                    write_subdirs_shorthand_rule(Globals, DepStream,
+                        ModuleName),
                     [".c", ".$O", ".pic_o", ".java", ".class", ".dll"], !IO)
             ;
                 UseSubdirs = no
@@ -679,20 +698,21 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
             ( if SourceFileName = default_source_file(ModuleName) then
                 true
             else
-            % The pattern rules in Mmake.rules won't work, since the source
-            % file name doesn't match the expected source file name for this
-            % module name. This can occur due to just the use of different
-            % source file names, or it can be due to the use of nested modules.
-            % So we need to output hard-coded rules in this case.
+                % The pattern rules in Mmake.rules won't work, since the
+                % source file name doesn't match the expected source file
+                % name for this module name. This can occur due to just the
+                % use of different source file names, or it can be due to
+                % the use of nested modules.  So we need to output
+                % hard-coded rules in this case.
                 %
-            % The rules output below won't work in the case of nested modules
-            % with parallel makes, because it will end up invoking the same
-            % command twice (since it produces two output files) at the same
-            % time.
+                % The rules output below won't work in the case of nested
+                % modules with parallel makes, because it will end up
+                % invoking the same command twice (since it produces two
+                % output files) at the same time.
                 %
                 % Any changes here will require corresponding changes to
-            % scripts/Mmake.rules. See that file for documentation
-            % on these rules.
+                % scripts/Mmake.rules. See that file for documentation on
+                % these rules.
 
                 io.write_strings(DepStream, [
                     "\n",
@@ -723,8 +743,8 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
             ),
 
             io.close_output(DepStream, !IO),
-        io.rename_file(TmpDependencyFileName, DependencyFileName, Result3,
-            !IO),
+            io.rename_file(TmpDependencyFileName, DependencyFileName,
+                Result3, !IO),
             (
                 Result3 = error(_),
                 % On some systems, we need to remove the existing file
@@ -735,8 +755,8 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                     maybe_write_string(Verbose, " failed.\n", !IO),
                     maybe_flush_output(Verbose, !IO),
                     io.error_message(Error4, ErrorMsg),
-                string.append_list(["can't remove file `", DependencyFileName,
-                    "': ", ErrorMsg], Message),
+                    string.append_list(["can't remove file `",
+                        DependencyFileName, "': ", ErrorMsg], Message),
                     report_error(Message, !IO)
                 ;
                     Result4 = ok,
@@ -748,8 +768,8 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                         maybe_flush_output(Verbose, !IO),
                         io.error_message(Error5, ErrorMsg),
                         string.append_list(["can't rename file `",
-                        TmpDependencyFileName, "' as `", DependencyFileName,
-                        "': ", ErrorMsg], Message),
+                            TmpDependencyFileName, "' as `",
+                            DependencyFileName, "': ", ErrorMsg], Message),
                         report_error(Message, !IO)
                     ;
                         Result5 = ok,
@@ -760,6 +780,7 @@ write_dependency_file(Globals, ModuleAndImports, AllDeps,
                 Result3 = ok,
                 maybe_write_string(Verbose, " done.\n", !IO)
             )
+        )
     ).
 
 %-----------------------------------------------------------------------------%
diff --git a/deep_profiler/conf.m b/deep_profiler/conf.m
index dc42450..11bdd1c 100644
--- a/deep_profiler/conf.m
+++ b/deep_profiler/conf.m
@@ -82,7 +82,8 @@ server_name(ServerName, !IO) :-
 :- pred server_name_2(string::out, io::di, io::uo) is det.
 
 server_name_2(ServerName, !IO) :-
-    io.make_temp(TmpFile, !IO),
+    io.make_temp_res(TmpFileResult, !IO),
+    ( TmpFileResult = ok(TmpFile),
         hostname_cmd(HostnameCmd),
         ServerRedirectCmd =
             string.format("%s > %s", [s(HostnameCmd), s(TmpFile)]),
@@ -102,11 +103,13 @@ server_name_2(ServerName, !IO) :-
                         then
                             ServerName = ServerNamePrime
                         else
-                        unexpected($module, $pred, "malformed server name")
+                            unexpected($module, $pred,
+                                "malformed server name")
                         )
                     ;
                         TmpReadRes = error(_, _),
-                    unexpected($module, $pred, "cannot read server's name")
+                        unexpected($module, $pred,
+                            "cannot read server's name")
                     ),
                     io.close_input(TmpStream, !IO)
                 ;
@@ -123,6 +126,10 @@ server_name_2(ServerName, !IO) :-
             Res1 = error(_),
             unexpected($module, $pred,
                 "cannot execute cmd to find the server's name")
+        )
+    ;
+        TmpFileResult = error(_),
+        unexpected($module, $pred, "Cannot create temporary file")
     ).
 
 :- pred maybe_server_port(maybe(string)::out, io::di, io::uo) is det.
diff --git a/library/io.m b/library/io.m
index 41a3f10..a944075 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1319,46 +1319,54 @@
 % File handling predicates.
 %
 
-    % make_temp(Name, !IO) creates an empty file whose name is different
-    % to the name of any existing file. Name is bound to the name of the file.
-    % It is the responsibility of the caller to delete the file when it
-    % is no longer required.
+    % make_temp(Result, !IO) creates an empty file whose name is different
+    % to the name of any existing file.  If successful Result returns the name
+    % of the file.  It is the responsibility of the caller to delete the file
+    % when it is no longer required.
     %
     % The file is placed in the directory returned by get_temp_directory/3.
     %
-    % Throws an io.error exception if the temporary file could not be created.
-    %
     % On the Erlang and Java backends, this does not attempt to create the file
     % with restrictive permissions (600 on Unix-like systems) and therefore
     % should not be used when security is required.
     %
+:- pred make_temp_res(io.res(string)::out, io::di, io::uo) is det.
+
+    % Like make_temp_res/3 except it throws an io.error exception if the
+    % temporary file could not be created.
+    %
+:- pragma obsolete(make_temp/3).
 :- pred make_temp(string::out, io::di, io::uo) is det.
 
-    % make_temp(Dir, Prefix, Name, !IO) creates an empty file whose
+    % make_temp(Dir, Prefix, Suffix, Result, !IO) creates an empty file whose
     % name is different to the name of any existing file. The file will reside
     % in the directory specified by Dir and will have a prefix using up to
-    % the first 5 characters of Prefix. Name is bound to the name of the
-    % file.  It is the responsibility of the caller to delete the file when it
-    % is no longer required.
-    %
-    % Throws an io.error exception if the temporary file could not be created.
+    % the first 5 characters of Prefix. If successful, Result returns the name
+    % of the file.  It is the responsibility of the caller to delete the file
+    % when it is no longer required.
     %
     % The C# backend has the following limitations:
     %   - Dir is ignored.
     %   - Prefix is ignored.
+    %   - Suffix is ignored.
+    %
+    % On the Erlang backend Suffix is ignored.
     %
     % On the Erlang and Java backends, this does not attempt to create the file
     % with restrictive permissions (600 on Unix-like systems) and therefore
     % should not be used when security is required.
     %
-:- pred make_temp(string::in, string::in, string::out, io::di, io::uo)
-    is det.
+:- pred make_temp_res(string::in, string::in, string::in, io.res(string)::out,
+    io::di, io::uo) is det.
 
-    % make_temp_directory(DirName, !IO) creates an empty directory whose name
-    % is different from the name of any existing directory.
+    % Same as make_temp_res except it does not take a suffix argument and
+    % throws an io.error exception if the temporary file could not be created.
     %
-    % Throws an io.error exception if the temporary directory could not be
-    % created.
+:- pragma obsolete(make_temp/5).
+:- pred make_temp(string::in, string::in, string::out, io::di, io::uo) is det.
+
+    % make_temp_directory(Result, !IO) creates an empty directory whose name
+    % is different from the name of any existing directory.
     %
     % On the C# backend this is insecure as the file permissions are not set
     % and this call does not test for an existing directory.
@@ -1367,31 +1375,29 @@
     %
     % This is unimplemented on the Erlang backend.
     %
-:- pred make_temp_directory(string::out, io::di, io::uo) is det.
+:- pred make_temp_directory(io.res(string)::out, io::di, io::uo) is det.
 
-    % make_temp_directory(Dir, Prefix, DirName, !IO) creates an empty directory
-    % whose name is different from the name of any existing directory.  The new
-    % directory will reside in the existing directory specified by `Dir' and
-    % will have a prefix using up to the first 5 characters of `Prefix'.
-    % DirName is bound to the name of the new directory. It is the
-    % responsibility of the program to delete the directory when it is no
-    % longer needed.
-    %
-    % Throws an io.error exception if the temporary directory could not be
-    % created.
+    % make_temp_directory(Dir, Prefix, Suffix, Result, !IO) creates an empty
+    % directory whose name is different from the name of any existing
+    % directory.  The new directory will reside in the existing directory
+    % specified by Dir and will have a prefix using up to the first 5
+    % characters of Prefix and a Suffix.  Result returns the name of the
+    % new directory. It is the responsibility of the program to delete the
+    % directory when it is no longer needed.
     %
     % The C# backend has the following limitations:
     %   - It does not attempt to create the file with restrictive permissions
     %     (600 on Unix-like systems) and therefore should not be used when
     %     security is required.
     %   - Prefix is ignored.
+    %   - Suffix is ignored.
     %
     % On the Java backend this is insecure as the file permissions are not set.
     %
     % This is unimplemented on the Erlang backend.
     %
-:- pred make_temp_directory(string::in, string::in, string::out,
-    io::di, io::uo) is det.
+:- pred make_temp_directory(string::in, string::in, string::in,
+    io.res(string)::out, io::di, io::uo) is det.
 
     % Test if the make_temp_directory predicates are available.  This is false
     % for the Erlang backends and either C backend without support for
@@ -10399,32 +10405,52 @@ command_line_argument(_, "") :-
 
 %---------------------------------------------------------------------------%
 
-make_temp(Name, !IO) :-
+make_temp_res(Result, !IO) :-
     get_temp_directory(Dir, !IO),
-    make_temp(Dir, "mtmp", Name, !IO).
+    make_temp_res(Dir, "mtmp", "", Result, !IO).
 
-make_temp(Dir, Prefix, Name, !IO) :-
-    do_make_temp(Dir, Prefix, char_to_string(dir.directory_separator),
+make_temp(Name, !IO) :-
+    make_temp_res(Result, !IO),
+    (
+        Result = ok(Name)
+    ;
+        Result = error(Error),
+        throw(Error)
+    ).
+
+make_temp_res(Dir, Prefix, Suffix, Result, !IO) :-
+    do_make_temp(Dir, Prefix, Suffix, char_to_string(dir.directory_separator),
         Name, Okay, Message, !IO),
     (
-        Okay = yes
+        Okay = yes,
+        Result = ok(Name)
     ;
         Okay = no,
-        throw_io_error(Message)
+        Result = error(make_io_error(Message))
     ).
 
-make_temp_directory(DirName, !IO) :-
+make_temp(Dir, Prefix, Name, !IO) :-
+    make_temp_res(Dir, Prefix, "", Result, !IO),
+    (
+        Result = ok(Name)
+    ;
+        Result = error(Error),
+        throw(Error)
+    ).
+
+make_temp_directory(Result, !IO) :-
     get_temp_directory(Dir, !IO),
-    make_temp_directory(Dir, "mtmp", DirName, !IO).
+    make_temp_directory(Dir, "mtmp", "", Result, !IO).
 
-make_temp_directory(Dir, Prefix, DirName, !IO) :-
-    do_make_temp_directory(Dir, Prefix,
+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
+        Okay = yes,
+        Result = ok(DirName)
     ;
         Okay = no,
-        throw_io_error(Message)
+        Result = error(make_io_error(Message))
     ).
 
 %-----------------------------------------------------------------------%
@@ -10440,12 +10466,11 @@ import java.util.Random;
 "
     public static Random ML_rand = new Random();
 
-    public static String makeTempName(String prefix)
+    public static String makeTempName(String prefix, String suffix)
     {
         StringBuilder sb = new StringBuilder();
 
         sb.append(prefix);
-
         // Make an 8-digit mixed case alpha-numeric code.
         for (int i = 0; i < 8; i++) {
             char c;
@@ -10460,13 +10485,14 @@ import java.util.Random;
             c = (char)c_num;
             sb.append(c);
         }
+        sb.append(suffix);
 
         return sb.toString();
     }
 ").
 
 :- pred do_make_temp(string::in, string::in, string::in,
-    string::out, bool::out, string::out, io::di, io::uo) is det.
+    string::in, string::out, bool::out, string::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.
@@ -10491,7 +10517,7 @@ import java.util.Random;
 ").
 
 :- pragma foreign_proc("C",
-    do_make_temp(Dir::in, Prefix::in, Sep::in, FileName::out,
+    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],
@@ -10499,8 +10525,8 @@ import java.util.Random;
 #ifdef MR_HAVE_MKSTEMP
     int err, fd;
 
-    FileName = MR_make_string(MR_ALLOC_ID, ""%s%s%.5sXXXXXX"",
-        Dir, Sep, Prefix);
+    FileName = MR_make_string(MR_ALLOC_ID, ""%s%s%.5sXXXXXX%s"",
+        Dir, Sep, Prefix, Suffix);
     fd = mkstemp(FileName);
     if (fd == -1) {
         ML_maybe_make_err_msg(MR_TRUE, errno,
@@ -10519,18 +10545,18 @@ import java.util.Random;
 #else
     /*
     ** Constructs a temporary name by concatenating Dir, `/', the first 5 chars
-    ** of Prefix, three hex digits, '.', and 3 more hex digits. The six digit
-    ** hex number is generated by starting with the pid of this process.
-    ** Uses `open(..., O_CREATE | O_EXCL, ...)' to create the file, checking
-    ** that there was no existing file with that name.
+    ** of Prefix, six hex digits, and Suffix. The six digit hex number is
+    ** generated by starting with the pid of this process.  Uses
+    ** `open(..., O_CREATE | O_EXCL, ...)' to create the file, checking that
+    ** there was no existing file with that name.
     */
     int     len, err, fd, num_tries;
     char    countstr[256];
     MR_Word filename_word;
     int     flags;
 
-    len = strlen(Dir) + 1 + 5 + 3 + 1 + 3 + 1;
-    /* Dir + / + Prefix + counter_high + . + counter_low + \\0 */
+    len = strlen(Dir) + 1 + 5 + 6 + strlen(Suffix) + 1;
+    /* Dir + / + Prefix + counter + Suffix + \\0 */
     MR_offset_incr_hp_atomic_msg(filename_word, 0,
         (len + sizeof(MR_Word)) / sizeof(MR_Word),
         MR_ALLOC_ID, ""string.string/0"");
@@ -10544,9 +10570,8 @@ import java.util.Random;
         strcpy(FileName, Dir);
         strcat(FileName, Sep);
         strncat(FileName, Prefix, 5);
-        strncat(FileName, countstr, 3);
-        strcat(FileName, ""."");
-        strncat(FileName, countstr + 3, 3);
+        strncat(FileName, countstr, 6);
+        strcat(FileName, Suffix);
         flags = O_WRONLY | O_CREAT | O_EXCL;
         do {
             #ifdef MR_WIN32
@@ -10577,7 +10602,7 @@ import java.util.Random;
 ").
 
 :- pragma foreign_proc("C#",
-    do_make_temp(_Dir::in, _Prefix::in, _Sep::in, FileName::out,
+    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, thread_safe],
 "{
@@ -10594,11 +10619,8 @@ import java.util.Random;
     }
 }").
 
-% For the Java implementation, io.make_temp/3 is overwritten directly,
-% since Java is capable of locating the default temp directory itself.
-
 :- pragma foreign_proc("Java",
-    do_make_temp(Dir::in, Prefix::in, _Sep::in, FileName::out,
+    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, thread_safe,
         may_not_duplicate],
@@ -10612,7 +10634,7 @@ import java.util.Random;
             Prefix = Prefix.substring(0, 5);
         }
 
-        new_file = new File(new File(Dir), makeTempName(Prefix));
+        new_file = new File(new File(Dir), makeTempName(Prefix, Suffix));
         if (new_file.createNewFile()) {
             FileName = new_file.getAbsolutePath();
             Okay = bool.YES;
@@ -10630,13 +10652,14 @@ import java.util.Random;
 ").
 
 :- pragma foreign_proc("Erlang",
-    do_make_temp(Dir::in, Prefix::in, Sep::in, FileName::out,
+    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],
 "
     DirStr = binary_to_list(Dir),
     PrefixStr = binary_to_list(Prefix),
+    SuffixStr = binary_to_list(Suffix),
     SepStr = binary_to_list(Sep),
 
     % Constructs a temporary name by concatenating Dir, Sep, Prefix
@@ -10658,7 +10681,7 @@ import java.util.Random;
     Seed = {A1 + Pid, A2, A3},
 
     case
-        mercury__io:'ML_do_make_temp_2'(DirStr, PrefixStr, SepStr,
+        mercury__io:'ML_do_make_temp_2'(DirStr, PrefixStr, SuffixStr, SepStr,
             MaxTries, Seed)
     of
         {ok, FileName0} ->
@@ -10673,19 +10696,19 @@ import java.util.Random;
 ").
 
 :- pragma foreign_decl("Erlang", local, "
-    -export(['ML_do_make_temp_2'/5]).
+    -export(['ML_do_make_temp_2'/6]).
 ").
 :- pragma foreign_code("Erlang", "
-    'ML_do_make_temp_2'(_, _, _, 0, _) ->
+    'ML_do_make_temp_2'(_, _, _, _, 0, _) ->
         {error, ""error opening temporary file""};
-    'ML_do_make_temp_2'(Dir, Prefix, Sep, Tries, Seed0) ->
+    'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep, Tries, Seed0) ->
         {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"",
-            [Dir, Sep, Prefix, R1, R2])),
+        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, Sep, Tries - 1, Seed);
+                'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep, Tries - 1, Seed);
             false ->
                 case file:open(FileName, [write, {encoding, utf8}]) of
                     {ok, IoDevice} ->
@@ -10696,27 +10719,28 @@ import java.util.Random;
                                 {error, file:format_error(Reason)}
                         end;
                     {error, _} ->
-                        'ML_do_make_temp_2'(Dir, Prefix, Sep, Tries - 1, Seed)
+                        'ML_do_make_temp_2'(Dir, Prefix, Suffix, Sep,
+                            Tries - 1, Seed)
                 end
         end.
 ").
 
 %-----------------------------------------------------------------------%
 
-:- pred do_make_temp_directory(string::in, string::in, string::in,
+:- 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.
 
 :- pragma foreign_proc("C",
-    do_make_temp_directory(Dir::in, Prefix::in, Sep::in, DirName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+    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,
         does_not_affect_liveness],
 "
 #ifdef MR_HAVE_MKDTEMP
     int err;
 
-    DirName = MR_make_string(MR_ALLOC_ID, ""%s%s%.5sXXXXXX"",
-        Dir, Sep, Prefix);
+    DirName = MR_make_string(MR_ALLOC_ID, ""%s%s%.5sXXXXXX%s"",
+        Dir, Sep, Prefix, Suffix);
     DirName = mkdtemp(DirName);
     if (DirName == NULL) {
         ML_maybe_make_err_msg(MR_TRUE, errno,
@@ -10737,8 +10761,8 @@ import java.util.Random;
 ").
 
 :- pragma foreign_proc("C#",
-    do_make_temp_directory(Dir::in, _Prefix::in, _Sep::in, DirName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+    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, thread_safe],
 "{
     try {
@@ -10761,8 +10785,8 @@ import java.util.Random;
 }").
 
 :- pragma foreign_proc("Java",
-    do_make_temp_directory(Dir::in, Prefix::in, _Sep::in, DirName::out,
-        Okay::out, ErrorMessage::out, _IO0::di, _IO::uo),
+    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, thread_safe,
         may_not_duplicate],
 "
@@ -10774,7 +10798,7 @@ import java.util.Random;
         Prefix = Prefix.substring(0, 5);
     }
 
-    new_dir = new File(new File(Dir), makeTempName(Prefix));
+    new_dir = new File(new File(Dir), makeTempName(Prefix, Suffix));
     if (new_dir.mkdir()) {
         DirName = new_dir.getAbsolutePath();
         Okay = bool.YES;
-- 
2.8.0.rc3


More information about the reviews mailing list