mkstemp
Stephen Weeks
MLton@sourcelight.com
Thu, 21 Jun 2001 18:10:33 -0700
> My claim, given that the amount of extra functionality I am getting from
> mkstemp() above and beyond just using open() is pretty small, is that you
> do NOT want the suffix argument. It just isn't useful very often. I realize
> that in MLton it is exactly what you want, but that isn't enough of an
> argument in my opinion. I vote for mkstemp being
> string -> string * TextIO.outstream
> and having MLton not use it for its temp files. (The output only argument
> is similarly based on frequency of use. In the old days tmp files were
> often used to save RAM between different parts of a program. These days
> that isn't very likely, so mainly it is to communicate between different
> programs, and this means that what the creator wants is just the output
> side.)
> Remember, part of the argument, especially given the name, is to be close
> to the C version. I would still not require the `XXXXXX' on the end of the
> string argument. This is different, but things have to be a bit different
> here because the C version uses the fact that its string arg is mutable.
OK. We will have both mkstemp and mkstemps. The reason I object to just having
mkstemp and not mkstemps is that it is trivial to implement mkstemp given
mkstemps, but not vice versa. And yes, the XXXXXX is definitely silly for
MLton.
Here is the final(?) implementation.
val MLton.TextIO.mkstemp: string -> string * TextIO.outstream
val MLton.TextIO.mkstemps:
{prefix: string, suffix: string} -> string * TextIO.outstream
local
val chars =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
val n = Word.fromInt (String.size chars)
val r: word ref = ref 0w0
in
fun tempName {prefix, suffix} =
let
val _ = r := Random.rand ()
val unique =
String.tabulate
(6, fn _ =>
let
val w = !r
val c = String.sub (chars,
Word.toInt (Word.mod (w, n)))
val _ = r := Word.div (w, n)
in c
end)
in
concat [prefix, unique, suffix]
end
end
fun mkstemps arg: string * outstream =
let
fun loop () =
let
val name = tempName arg
open Posix.FileSys
in
(name,
newOut (createf (name, O_WRONLY, O.flags [O.excl],
let open S
in flags [irusr, iwusr]
end)))
end handle e as PosixError.SysErr (_, SOME s) =>
if s = Posix.Error.exist
then loop ()
else raise e
in
loop ()
end
fun mkstemp s = mkstemps {prefix = s, suffix = ""}