кстати, HostFiles/Lin можно ещё немножко улучшить. не уверен, что это очень нужно именно сейчас, но с другой стороны — это и не деструктивно. вкрации(ц): в процедуре `Delete()` (она внутренняя, непубличная) использующийся открытый файл можно просто удалять, а не переименовывать во временное имя. в винде так нельзя, а в линуксах удаление открытого файла разрешено, и не убивает файловые дескрипторы.
это позволит избавиться от кучи временных файлов, которые возникают при сохранении документов. потому что среда при сохранении делает так: пишет новый анонимный файл, потом его регистрирует под именем старого; но старый всё ещё открыт. таким образом у нас появляется временный «удалённый» файл, который нужен низачем, и будет удалён по выходу из среды (потому что винда не позволяет удалять открытые файлы, а лин-филес просто калька с виндового). короче, вот так можно:
Код:
PROCEDURE Delete (IN fname, path: FullName; OUT res: INTEGER);
VAR
num, n: INTEGER;
f: File; new: FullName;
attr: SET;
fn, nn: ShortName;
buf: Libc.stat_t;
isDir: BOOLEAN;
BEGIN ASSERT(fname # '', 20);
f := ThisFile(fname); NameToLocal(fname, fn);
IF f = NIL THEN
IF Libc.remove(fn) = 0 THEN res := ok
ELSE
res := Libc.fflush(0);
IF Libc.remove(fn) = 0 THEN res := ok ELSE res := Libc_errno() END
END
ELSE (* still in use => make it anonymous *)
(* k8: we can safely delete it; this will not invalidate file handles;
one gotcha: the file should be opened; for non-opened-yet files, use the old method *)
IF f.ref # invalid THEN
IF Libc.remove(fn) = 0 THEN res := ok
ELSE
res := Libc.fflush(0);
IF Libc.remove(fn) = 0 THEN res := ok ELSE res := Libc_errno() END
END;
IF res = ok THEN (* it is hidden, and has no name anymore *)
f.state := hidden; f.name := ''
END;
ELSE (* old method *)
CloseFileHandle(f, ^res);
Stat(f.name, buf, res);
ModeToAttr(buf.st_mode, attr, isDir);
IF (res = ok) & ~(Files.readOnly IN attr) THEN
num := Libc.clock(); n := 200;
REPEAT
GetTempFileName(path, new, num); INC(num); DEC(n);
NameToLocal(new, nn);
MoveFile(fn, nn, res);
UNTIL (res # fileExistsErr) OR (n = 0);
IF res = ok THEN
f.state := hidden; f.name := new$
END
ELSE
res := writeProtectedErr
END
END
END
END Delete;
также в `CreateFile()` можно использовать стандартную либц-функцию для создания безымянных временных файлов (потому что временные файлы по контракту нельзя регистрировать в файловой системе):
Код:
PROCEDURE CreateFile (f: File; OUT res: INTEGER);
VAR num, n: INTEGER;
BEGIN
IF f.name = '' THEN
(* k8: temp files cannot be registered, and need no name *)
IF f.state = temp THEN
f.ref := Libc.tmpfile();
IF f.ref = invalid THEN res := Libc_errno() ELSE res := ok END
ELSE
num := Libc.clock(); n := 200;
REPEAT
GetTempFileName(f.loc.path, f.name, num); INC(num); DEC(n);
OpenFile(f, create, f.name, f.ref, res)
UNTIL (res # fileExistsErr) OR (n = 0)
END
ELSE
OpenFile(f, f.state, f.name, f.ref, res)
END
END CreateFile;
это идеологически правильней, нежели создавать файлы с временными именами, потому что `tmpfile()` правильно сделает такие файлы в "/tmp".