## winix-text-file-io-driver-for-win32--premicrothread.pkg
#
# Here we implement win32-specific text file I/O support.
#
# This file gets used in:
#
#
src/lib/std/src/win32/winix-text-file-for-win32--premicrothread.pkg#
# Compare to:
#
#
src/lib/std/src/win32/winix-data-file-io-driver-for-win32--premicrothread.pkg#
src/lib/std/src/posix/winix-text-file-io-driver-for-posix--premicrothread.pkg#
src/lib/src/lib/thread-kit/src/win32/winix-data-file-io-driver-for-win32.pkg#
local
package one_word_unt = Word32Imp
package os = winix_guts
package string = StringImp
package int = int_guts
in
package winix_text_file_io_driver_for_win32__premicrothread
:
api
include api Winix_Base_File_Io_Driver_For_Os__Premicrothread
my stdin: Void -> filereaders_and_filewriters::Reader
my stdout: Void -> filereaders_and_filewriters::Writer
my stderr: Void -> filereaders_and_filewriters::Writer
my string_reader: String -> filereaders_and_filewriters::Reader
end
{
package drv = winix_base_text_file_io_driver_for_posix__premicrothread
package W32FS = Win32::file_system
package W32IO = Win32::IO
package W32G = Win32::general
package v = vector_of_chars
type File_Descriptor = W32G::hndl
say = W32G::logMsg
fun announce s x y = (
# * say "announce winix_text_file_io_driver_for_win32__premicrothread: "; say (s: String); say "\n"; *
x y)
bufferSzB = 4096
fun mkReader { initablekMode=FALSE, ... } =
raise exception DIE "Nonblocking IO not supported"; # We never support blocking I/O these days, so this code will need rewriting.
| mkReader { fd, name, initablekMode } =
let closed = REF FALSE
fun ensureOpen f x =
if *closed then raise exception io::CLOSED_IO_STREAM else f x
blocking = REF initablekMode
iod = W32FS::hndlToIOD fd
fun readVec n = announce "readVecTxt"
W32IO::readVecTxt (W32FS::IODToHndl iod, n)
fun readArr arg = announce "readArrTxt"
W32IO::readArrTxt (W32FS::IODToHndl iod, arg)
fun close () =
if *closed then ()
else (closed:=TRUE; announce "close"
W32IO::close (W32FS::IODToHndl iod))
in
drv::FILEREADER {
name = name,
chunkSize = bufferSzB,
readVec = THE (ensureOpen readVec),
readArr = THE (ensureOpen readArr),
readVecNB = NULL,
readArrNB = NULL,
block = NULL,
max_readable_without_blocking = NULL,
avail = \\ () => NULL,
getPos = NULL,
setPos = NULL,
endPos = NULL,
verifyPos = NULL,
close = close,
ioDesc = THE iod
}
end
shareAll = one_word_unt::bitwise_or (W32IO::FILE_SHARE_READ,
W32IO::FILE_SHARE_WRITE)
fun checkHndl name h =
if W32G::isValidHandle h then h
else raise exception winix__premicrothread::RUNTIME_EXCEPTION ("winix_text_file_io_driver_for_win32__premicrothread:"$name$": failed", NULL)
fun openRd name =
mkReader {
fd = checkHndl "openRd"
(announce "createFile"
W32IO::createFile {
name=name,
access=W32IO::GENERIC_READ,
share=shareAll,
mode=W32IO::OPEN_EXISTING,
attributes=0wx0
} ),
name = name,
initablekMode = TRUE
}
fun mkWriter { initablekMode=FALSE, ... } =
raise exception DIE "Nonblocking IO not supported"; # We never support blocking I/O these days, so this code will need rewriting.
| mkWriter { fd, name, initablekMode, appendMode, chunkSize } =
let closed = REF FALSE
blocking = REF initablekMode
fun ensureOpen () =
if *closed then raise exception io::CLOSED_IO_STREAM else ()
iod = W32FS::hndlToIOD fd
fun writeVec v = announce "writeVec"
W32IO::writeVecTxt (W32FS::IODToHndl iod, v)
fun writeArr v = announce "writeArr"
W32IO::writeArrTxt (W32FS::IODToHndl iod, v)
fun close () =
if *closed then ()
else (closed:=TRUE;
announce "close"
W32IO::close (W32FS::IODToHndl iod))
in
drv::FILEWRITER {
name = name,
chunkSize = chunkSize,
writeVec = THE writeVec,
writeArr = THE writeArr,
writeVecNB = NULL,
writeArrNB = NULL,
block = NULL,
canOutput = NULL,
getPos = NULL,
setPos = NULL,
endPos = NULL,
verifyPos = NULL,
close = close,
ioDesc = THE iod
}
end
fun openWr name =
mkWriter {
fd = checkHndl "openWr"
(announce "createFile"
W32IO::createFile {
name=name,
access=W32IO::GENERIC_WRITE,
share=shareAll,
mode=W32IO::CREATE_ALWAYS,
attributes=W32FS::FILE_ATTRIBUTE_NORMAL
} ),
name = name,
initablekMode = TRUE,
appendMode = FALSE,
chunkSize = bufferSzB
}
fun openApp name =
let h = checkHndl "openApp"
(announce "createFile"
W32IO::createFile {
name=name,
access=W32IO::GENERIC_WRITE,
share=shareAll,
mode=W32IO::OPEN_EXISTING,
attributes=W32FS::FILE_ATTRIBUTE_NORMAL
} )
announce "setFilePointer'"
W32IO::setFilePointer' (h, 0wx0, W32IO::FILE_END)
in
mkWriter {
fd = h,
name = name,
initablekMode = TRUE,
appendMode = TRUE,
chunkSize = bufferSzB
}
end
fun stdin () =
let h = W32IO::getStdHandle (W32IO::STD_INPUT_HANDLE)
in
if W32G::isValidHandle h then
mkReader { fd = h,
name = "<stdin>",
initablekMode = TRUE }
else
raise exception winix__premicrothread::RUNTIME_EXCEPTION("winix_text_file_io_driver_for_win32__premicrothread: can't get stdin", NULL)
end
fun stdout () =
let h = W32IO::getStdHandle (W32IO::STD_OUTPUT_HANDLE)
in
if W32G::isValidHandle h then
mkWriter { fd = h,
name = "<stdout>",
initablekMode = TRUE,
appendMode = TRUE,
chunkSize = bufferSzB }
else
raise exception winix__premicrothread::RUNTIME_EXCEPTION("winix_text_file_io_driver_for_win32__premicrothread: can't get stdout", NULL)
end
fun stderr () =
let h = W32IO::getStdHandle (W32IO::STD_ERROR_HANDLE)
in
if W32G::isValidHandle h then
mkWriter { fd = h,
name = "<stderr>",
initablekMode = TRUE,
appendMode = TRUE,
chunkSize = bufferSzB }
else
raise exception winix__premicrothread::RUNTIME_EXCEPTION("winix_text_file_io_driver_for_win32__premicrothread: can't get stderr", NULL)
end
fun string_reader src = # stolen wholesale from winix-text-file-io-driver-for-posix--premicrothread.pkg
let pos = REF 0
closed = REF FALSE
fun checkClosed () = if *closed then raise exception io::CLOSED_IO_STREAM else ()
len = string::size src
fun avail () = (len - *pos)
fun readV n =
let p = *pos
m = int::min (n, len-p)
in
checkClosed ();
pos := p+m;
# * NOTE: could use unchecked operations here *
string::substring (src, p, m)
end
fun readA asl =
let p = *pos
my (buf, i, n) = rw_vector_slice_of_chars::base asl
m = int::min (n, len - p)
in
checkClosed ();
pos := p+m;
rw_vector_slice_of_chars::copyVec { src = vector_slice_of_chars::slice
(src, p, THE m),
dst = buf, di = i };
m
end
fun getPos () = (checkClosed(); *pos)
in
drv::FILEREADER {
name = "<string>",
chunkSize = len,
readVec = THE readV,
readArr = THE readA,
readVecNB = THE (THE o readV),
readArrNB = THE (THE o readA),
block = THE checkClosed,
max_readable_without_blocking = THE (\\ () => (checkClosed(); TRUE)),
avail = THE o avail,
getPos = THE getPos,
setPos = THE (\\ i => (checkClosed();
if (i < 0) or (len < i)
then raise exception INDEX_OUT_OF_BOUNDS
pos := i)),
endPos = THE (\\ () => (checkClosed(); len)),
verifyPos = THE getPos,
close = \\ () => closed := TRUE,
ioDesc = NULL
}
end
}
end