OpenLN := proc(N::digit, O::symbol, F::{string, symbol}) local a k h p L t K, , , , , , ; assign(K = cat "",( F)), `if`(6 < N, ERROR( "the first argument should be less than 6, but has received <%1>", N), `if`( member O, {( 'open', 'fopen'}), assign(h = iostatus( ), L = { }, a = DoF1(K)), ERROR( "mode of opening should be {open, fopen}, but has received <%1>"O)));, if a = 2 then error "file <%1> is already open", F elif member(a, {3, 4}) then error "<%1> is a directory", K end if; if nargs = 3 then L := {k $ (k = 0 .. 6)} else seq(assign(' 'L = {op(L), h k[ ][1]}), k = 4 .. nops(h)), assign(p = {k $ (k = 0 .. 6)} minus L) end if; if member(N L, ) then error "logical I/O channel <%1> is busy", N end if; member(N, p, 't'), seq(open(cat(currentdir( ), "/$Art17_Kr9$.", k), 'WRITE'), k = 1 .. t − 1); try O(K, seq(args[ ]k , k = 4 .. nargs)), p minus {N}, seq(fremove cat(( currentdir( ), "/$Art17_Kr9$.", k)), k = 1 .. t − 1) catch "too many files already open": seq(fremove(cat(currentdir( ), "/$Art17_Kr9$.", k)), k = 1 .. t − 1) catch "file I/O error": seq(fremove cat(( currentdir( ), "/$Art17_Kr9$.", k)), k = 1 .. t − 1); error "access error to datafile <%1>; possibly, file has attribute {readonly\ hidden, or/and system}", F |
end try end proc > OpenLN(3, open, "D:/Books/bin.xls", 'READ'), iostatus(); 3, {0, 1, 2, 4, 5}, [2, 0, 7, [3, "D:/Books/bin.xls", RAW, FD = 14, READ, BINARY], [6, "C:/Temp/Tallinn", RAW, FD = 17, WRITE, BINARY]] |
Успешный вызов процедуры OpenLN(N, O,F, parms) возвращает 2-элементную последовательность, чей первый элемент определяет номер логического канала в/в, т.е. N, тогда как второй – множество остающихся номеров открытых каналов. Четвертый аргумент parms определяет остальные фактические аргументы, зависящие от функции открытия O {open, fopen}. Наконец, F-аргумент определяет имя либо полный путь открываемого файла данных. С рядом наших других полезных процедур, относящихся к открытию файлов данных, можно ознакомиться в [41,103,108,109].
В дальнейшем нам понадобится ряд понятий, хорошо известных имеющему опыт программирования читателю. Это относится к таким понятиям как типы файлов: буферированные (STREAM) и небуферированные (RAW). Какой-либо особой разницы между ними основные средства доступа Maple-языка не делают, однако в их реализации первые во временном отношении более реактивны, т.к. используют механизм буферизации [12]. Небуферированный же тип файлов используется, как правило, при необходимости оперативного запроса состояния того или иного ресурса ЭВМ. Тогда как в общем случае следует использовать буферированный тип файлов, который по умолчанию используется большинством функций доступа Maple-языка. В более простой терминологии работа (чтение/запись) с буферированными файлами производится не напрямую, а через специальный буфер, обеспечивающий накопление информации для возможности создания более крупных информационных блоков обмена, тогда как работа с небуферированным файлом производится напрямую, минуя какой-либо буфер. Второй подход повышает оперативность доступа к файлу, но существенно снижает его реактивность при интенсивном режиме обмена данными. Функции языка (например, iostatus), возвращающие состояние системы в/в, для идентификации буферированных и небуферированных файлов используют соответственно идентификаторы STREAM и RAW.
Большинство операционных сред (MS-DOS, Windows, MAC, VMS и др.) различают файлы, рассматривая их организацию в виде последовательности символов (текстовые) либо последовательности байтов (бинарные). Основой различия является выделение в них специальных управляющих байтов, идентифицирующих состояние «перевод строки и возврат каретки». Данное состояние исторически восходит к принципам работы пишущих машинок по созданию текстовых документов и в консоли ЭВМ реализуется Enterклавишей. В среде некоторых других операционных систем различие между файлами обоих типов могут носить несколько иной характер, который невидим на уровне рассматриваемых нами средств доступа Maple-языка.
Реализация состояния «перевод строки и возврат каретки» зависит от используемой операционной среды ЭВМ. В среде Maple-языка данное состояние идентифицируется одним символом, а в строчных конструкциях оно кодируется символами “\n”. Международный ASCII-стандарт для этих целей использует символ с десятичным кодом <10>, тогда как в операционных средах MS-DОS, Windows, VMS указанное состояние представляется парой символов с десятичными кодами <13,10>, а MAC-система использует для этих целей только один символ с десятичным кодом <13>. При реализации доступа (чтение/запись) к текстовому файлу средства доступа при обнаружении символов, определяющих состояние «перевод строки и возврат каретки», производят соответствующие действия, рассматриваемые ниже. Тогда как для бинарных файлов средства доступа рассматривают все составляющие их символы как последовательность равноценных байтов. Средства доступа Maple-языка поддерживают работу как с текстовыми, так и с бинарными файлами. Однако следует иметь в виду, что при использовании пакета в среде Unixподобных систем средства доступа Maple-языка отождествляют оба типа файлов, полагая все файлы бинарными. Функции доступа Maple-языка, различающие оба типа файлов, используют для них соответственно идентификаторы TEXT (текстовый) и BINARY (бинарный).
На внутреннем уровне ядро пакета средствами внутренней I/O-библиотеки (iolib-библиотеки) обеспечивает доступ к файлам данных следующих пяти видов:
STREAM – буферированный файл,соответствующий стандарту I/O-библиотеки С-языка;
RAW – небуферированный файл,соответствующий стандарту Unix- и ряда других сред; PIPE – двухконцевой канал, соответствующий Unix-стандарту и поддерживаемый толь- ко Unix-платформой;
PROCESS – канал, который одним концом связан с другим процессом по Unix-стандарту; DIRECT – прямой доступ к текущему (по умолчанию) или высшего уровня (терминал) потоку ввода/вывода (например, одновременный ввод запросов на обслуживание и по- лучение возвращаемых результатов их обработки в интерактивном режиме работы с ядром Maple-пакета).
Для обеспечения доступа к файлу любого из указанных пяти видов он должен быть предварительно открыт в одном из двух режимов доступа: READ (на чтение) или WRITE (на запись). При этом, режим открытия определяется или явно в момент вызова функций открытия: fopen, open, pipe или popen, либо неявно в результате вызова ряда функций в/в внутренней I/О-библиотеки ядра пакета. Если файл вида {STREAM|RAW|DIRECT} открыт в READ-режиме доступа, то попытка записи в него информации автоматически закрывает его с последующим переоткрытием в WRITE-режиме доступа к последней сканированной до этого позиции файла. Данная особенность позволяет перлюстрировать файл до нужной позиции, а затем переоткрывать его на запись с данной позиции. Другие виды файлов, открытые явно, не могут изменять режима доступа без их предварительного явного закрытия. Попытка записи в файл, отмеченный как «только для чтения (readonly)» вызывает ошибочную ситуацию с соответствующей диагностикой. Детальнее реакция ядра пакета на использование указанных режимов доступа будет рассмотрена ниже. Функции доступа Maple-языка, использующие в своих форматах типы режима, применяют для них соответственно специальные идентификаторы READ (чтение) и WRITE (запись). При этом, следует констатировать, что для целого ряда пакетных имен, включая READ и WRITE, не предусмотрен protected-атрибут, что при их кодировании требует осмотрительности и использования невычисленного формата, например, 'READ'.
С целью устранения данной недоработки нами была создана процедура Lprot.
Lprot := proc() local a b c d k, , , , ; assign(c = { }, d = [ ]); if nargs ≠ 0 then for k in [args] do if member(CF( )k , {map(CF, {libname})}) then d := [op(d), k] elif type(k, 'symbol') then c := {op(c), k} end if end do end if; if type(MkDir, 'libobj') then |
a := [op(march('list', _libobj)), seq(op(march('list', k)), k = d)] elif d ≠ [ ] then a := [seq(op march(( 'list k', )), k = d)] else error "user libraries are absent in the predefined variable <libname>" end if; protect `if`(( c = { }, NULL, op( )c ), all APPEND Arguments arity assignable, , , , , assignable1, binary, BINARY, Break, boolproc, builtin, byte, bytes, chkpnt, coincidence complex complex1 false, , , , ,γ ∞, true Catalan FAIL, , , π, correct, create Cycle Decimal decimal default del delel delel1 delete digit dir, , , , , , , , , , , dirax direct display element Empty End Exit exit_type exprseq extract, , , , , , , , , , file file1 Fin fpath frame globals heap hold insensitive insert inside, , , , , , , , , , , invalid, left, letter, lex_tab, libobj, list, list1, listlist, listlist1, locals, lower, Lower lowercase LRM mla mlib Mod mod1 Next nestlist nonsingular, , , , , , , , , , NRM only package path plotopt plot3dopt prn, , , , , , , procname, pvl RAW, , READ realnum rem_tab Repeat restore right rlb Roman Russian, , , , , , , , , sensitive seqn sequent set set1 setset shape Special ssign ssll, , , , , , , , , , statement, sublist, Table, terminal, TEXT, toc2005, upper, Upper, uppercase Variable VGS WRITE variable, , , , , seq(`if`(b[1][1 .. 2] = ":-", NULL, cat(``, b[1][1 .. -3])), b = a)) end proc |
Процедура своим вызовом Lprot() присваивает protected-атрибут именам пакета и нашей Библиотеки [109], не имеющих такого атрибута. Тогда как по вызову Lprot(args) дополнительно получают данный атрибут и имена, определенные необязательным аргументом.
В отличие от операционной Unix-системы, рассматривающей файлы как последовательности байтов, большинство других операционных сред и оболочек типизируют файлы, классифицируя их на два основных типа TEXT (текстовые) и BINARY (бинарные). Оба типа оперируют с последовательностями соответственно символов и байтов. Для представления «конца строки» (записи) в TEXT-файлах на платформах D0S и Windows служит 2-х символьный идентификатор hex(0D0A) «перевода строки и возврата каретки». При явном открытии файла STREAM-вида имеется возможность определять его тип, тогда как при неявном открытии его тип определяется контекстуально. Файлы, отличные от STREAMвида (исключая DIRECT), автоматически открываются как BINARY-файлы. Тогда как файлы DIRECT-вида автоматически открываются как TEXT-файлы.