8. ОПЕРАЦИИ С ФАЙЛАМИ

Описанная выше команда #d определяет элементы массивов по значениям. Но часто бывает полезно записать значения в файл и потом считывать эти значения в другой программе или в той же самой, но в другой день. Это очень важный и совершенно необходимый элемент при работе на компьютере. Работу с файлами выполняют команды (io) input-output и (f) file. В этих командах параметр [file] указывает путь к файлу. Тут есть некие правила игры, которые необходимо соблюдать. Первоначально я предполагал, что программа интерпретатора не будет выходить за пределы своей папки. То есть исходно путь к файлу начинается от папки интерпретатора. Внутри этой папки могут быть другие папки и уровни вложений не ограничены. Удобно использовать определение "рабочей папки", которая переопределяет папку интерпретатора. Если рабочая папка установлена, то достаточно указать путь к файлу относительно нее. То есть, если рабочая папка задана правильно, то это позволяет сократить запись. Однако некоторые операции не используют рабочую папку. Об этом оговорено специально.

Есть существенное ограничение -- значение параметра [file] не может быть длиннее 42 символов, я уже писал об этом раньше. Так что не увлекайтесь длинными именами. Если имя файла будет длиннее, его придется переименовать. Есть способ обойти это ограничение. Об этом написано ниже по тексту. Полезно также обсудить два различных способа задания текстовых параметров. Их можно задавать прямым текстом, например,
[file=mydata.dat;]
и при этом текст должен обязательно заканчиваться символом [;] как все операторы присваивания (или пробелом, но я это не использую). Но можно задавать и форматированным текстом. При этом первым символом должен быть символ текстового формата [\], а заканчиваться такая строка должна символами \E и без точки с запятой. Хотя все текстовые параметры можно так задавать, этот режим в основном используется только для задания имени файла и, главным образом, путем указания текстовой ссылки. Это очень удобно в циклах. Допустим вам в цикле необходимо прочитать 50 файлов с именами: img01.png,   img02.png,   . . . ,   img50.png. Тогда код может быть таким.

 # m=0; ... #pr img\E # a=s(4); b=s(5);
 #rep 50 # m=m+1; ...
 #io [op=rb; fir=i(1); n=256; file=\Ta b\I-2 m;.png\E]
 #end 

Естественно, что файл, задаваемый куском текстового массива, не должен начинаться с символа [\]. Но это ограничение очень слабое. Указанный прием называется динамической генерацией имени файла. Более сложные имена файлов можно сначала все напечатать, а затем указывать текстовыми ссылками, например \Tp\E, или генерируя индекс ссылки (имя строки) через параметр цикла. Но можно и не использовать текстовую ссылку при задании файла текстом. Вместо этого достаточно задать первый символ текста в виде [\uN;], где вместо N поставить юникод первого символа.

Со временем захотелось работать со всеми файлами на компьютере. Работать со всеми файлами на компьютере по их абсолютным адресам иногда бывает полезно. Это реализуется указанием рабочей папки как "null". В стандартном режиме это соответствует папке интерпретатора. Но если в параметр file записать полный адрес, начиная с буквы диска, то используется полный адрес. Фактически программа проверяет второй символ адреса на совпадение с символом (:). Это работает только в системе Виндовс. Но полный адрес может иметь очень большой размер, а размер параметра file ограничен 42 символами после развертки всех текстовых ссылок. Чтобы снять это ограничение введен специальный режим [file=arg;]. В этом случае адрес файла надо задавать первым аргументом команды, и отсутствие аргумента фиксируется как ошибка. При задании абсолютных адресов разумно всегда использовать этот вариант.

Описание начнем с первой команды

.

 #io [op=; fir=; n=; file=; form=; mo=; le=;]

Она использует 4 текстовых параметра и один числовой параметр. Параметр [op] задает тип операции, который кодируется двумя буквами. Первая буква может быть: [r] (read - прочитать из файла) или [w] (write -записать в файл). Вторая буква может быть: [f] (format - запись числовых значений текстом по формату) или [b] (byte - запись данных типа byte) или [d] (data - запись данных типа float, int или double) или [t] (text - запись текстовых данных). Итак возможны операции

    rf wf rb wb rd wd rt wt

При этом параметр [fir] (first) указывает первый элемент массива, как это было в командах #d и #pas, то есть указывается и тип массива и первый индекс, например, r(35). Параметр [n] (number) указывает сколько элементов надо записать или считать. Параметр [form] (format - формат записи чисел текстом) используется только в одной операции [wf], то есть запись по формату.

В операции [rf], то есть чтение по формату, автоматически читаются все возможные форматы и специально нет смысла указывать формат. Но формат в этом случае все же используется для передачи другой информации. Он должен иметь структуру

 [form=*N;]

где вместо N должно быть число или переменная с целым значением, которое указывает сколько строк в файле будет пропущено прежде чем начнется чтение чисел.

Запись чисел по формату операцией [wf] возможна только из массивов i() и r(). Если необходимо записать числа из других массивов, то их сначала надо переслать в эти командой #pas. Параметр [form] тоже ограничен по длине 42 символами, но все возможные форматы имеют меньшую длину, так что это ограничение формальное. Наиболее простым форматом является такой

 [form=*N;]

где вместо N должно быть число, указывающее сколько чисел надо напечатать на одной строке. Этот формат эквивалентен текстовому формату \G (см. раздел 4 про текстовые форматы). Признаком конца строки будет ASCII код 10, то есть как в операционной системе UNIX и как в Java. Есть еще второй формат, который имеет структуру

 [form=EN.M.L;]

где вместо N должно быть число, указывающее сколько чисел надо напечатать на одной строке, вместо M должно быть число, указывающее сколько позиций (символов) должно быть отведено на одно число, вместо L должно быть число, указывающее сколько позиций отводится для дробной части числа. Точки между числами служат разделителями. По этому формату строка заканчивается двумя ASCII кодами 13,10, а числа записываются в экспоненциальной форме с E и десятичным разделителем служит точка. Необходимо, чтобы M было больше, чем L+7. Этот формат эквивалентен текстовому формату \B. Например, 6 чисел, записанных по формату [form=E3.10.3;] сгенерируют текст

  1.000E+00 2.000E+00 3.000E+00
  4.000E+00 5.000E+00 6.000E+00

Больше форматов нет. Но реально, можно организовать сколько угодно сложный формат, если сначала записать текст в текстовый массив t(), а затем скопировать его в файл. Теперь перейдем к операциям [rt] и [wt]. Эти операции могут работать только с текстовым массивом t(), поэтому параметр [fir] должен указывать только на t(), иначе будет ошибка.

Операция [rt] просто заполняет некоторую часть массива t() из файла, начиная с элемента, указанного [fir] и ровно [n] элементов. При этом сначала считывается весь файл, как текст строка за строкой, затем содержимое конвертируется в массив юникодов и берется нужное число символов. Этот режим проверялся только на первых 127 юникодах и как он работает на остальных можно проверить экспериментальным путем. После выполнения операции параметр s(4) содержит индекс первого записанного элемента в t(), а параметр s(5) - число элементов. Это общий принцип записи в текстовый массив, точно так же поступает команда #pri . В любой момент параметр s(6) показывает размер записанной части массива t(). В настоящее время по этой операции можно также считывать тексты из файлов, записанных внутри jar-файла программы в папку [resources]. Это удобно в режиме использования программы в виде спец-окна или проигрывателя (см. главу 25). Для этого перед именем файла надо поставить символ &.

Операция [wt] наоборот, сначала конвертирует нужный кусок массива юникодов в текст и затем записывает в файл строка за строкой. При этом файл записывается целиком, а если он существовал раньше, то полностью переписывается. В этом случае признак конца строки соответсвует той операционной системе, которая используется. Например, в Windows это [13,10], хотя изначально в текстовом массиве было просто [10]. Теперь ясно, что образ будущего файла можно сформировать с помощью команды #pri и затем перенести в файл из t() целиком. При этом можно использовать всю мощь форматов этой команды.

Операции [rd] и [wd] позволяют считывать и записывать числа в компьютерном коде. Это самая сжатая форма записи и она особенно полезна для записи очень больших массивов. В этом случае дополнительно используется параметр [mo] (mode) для указания формата записи чисел. Если [mo=1;], то числа записываются и считываются в формате (float), то есть вещественные числа длиной 4 байта. Если [mo=2;], то используется формат (int) целых чисел длиной 4 байта. Если [mo=3;], то используется формат (double) для вещественных чисел длиной 8 байт. Если [mo=4;], то используется формат (short), то есть двухбайтовые знаковые целые числа. Порядок байтов как в Java, то есть старшие слева. Для данных, записанных в Windows программах, необходимо сначала перевернуть порядок байтов какой-либо специальной процедурой. Сама ACL-программа как записывает, так и считывает и проблем не возникает.

Наконец, если [mo=5;] то команда считывает и записывает двухбайтовые целые числа без знака. При этом порядок байтов регулирует параметр [ord], если он равен нулю, то первый байт является старшим, второй младшим, как в Java, а если он отличен от нуля, например, равен 1, то младший байт первый, старший второй, как в Windows. Такой формат записи чисел используется детекторами излучения и записывается в графические файлы с расширением tif или edf. Данные считываются из файла не с самого начала, а после пропуска определенного числа байтов, задаваемого параметром [le], и не весь файл, а столько чисел, сколько указано параметром [n]. А вот записываются числа в новый файл с самого начала. Если файл существует, то он переписывается заново. Узнать размер файла при чтении можно с помощью команды #file (см. далее). Если программа считывает больше данных, чем было записано, то возникающая ошибка не блокируется и Java-интерпретатор выдаст сообщение на Терминал, если программа запущена из bat-файла. Так что надо быть внимательным. Это недоработка, каюсь.

Следует также не забывать, что параметр [le] позволяет пропускать любое число данных перед чтением. Но указывается именно число байтов, а не чисел. Так что число пропускаемых чисел должно быть умножено на длину числа (4 или 8). При этом, если [le] отлично от нуля, то параметр s(1) возвращает реальное число байтов, сколько было на самом деле пропущено. Это число, практически всегда совпадает с тем, которое было заказано параметром [le], но в случае проблем можно проверить операцию, распечатав параметр s(1). В настоящее время по этой операции можно также считывать данные из файлов, записанных внутри jar-файла программы в папку [resources]. Это удобно в режиме использования программы в виде спец-окна или проигрывателя (см. главу 25). Для этого перед именем файла надо поставить символ &.

Операция [rb] позволяет считывать байты файла как целые числа в диапазоне от -128 до 127. В этом случае используется параметр [le] (length), который определяет число пропущенных байтов в файле, перед чтением. То есть реально считывание происходит не с первого байта, а с байта, номер которого [le]+1. Если чтение происходит в текстовый массив, то к отрицательным значениям добавляется 1104, что переводит русские ASCII коды в формате Windows в русские юникоды. Это позволяет читать русские книги в текстовом формате Windows.

При записи операцией [wb] значения элементов массивов конвертируются в байты. При этом русские юникоды массива t() переводятся в отрицательные значения вычитанием 1104. Так же точно числа в диапазоне от 128 до 255 из целого массива i() переводятся в отрицательные вычитанием числа 256. Файл записывается сначала и заново создается. Эти операции позволяют манипулировать содержимым файла произвольным образом. Но следует помнить, что байтов в файле много, а ACL -- язык не быстрый. Поэтому манипулировать разумно только с относительно короткими файлами.

* * * * *

Работа с файлами не ограничивается только записью и чтением данных. Есть очень много других нужных и полезных операций. По этой причине в ACL сделана специальная команда, которая так и называется #file, а короче #f. Эта команда имеет очень много операций, причем операции объединены в одну команду лишь по той причине, что они все работают с файлами. На самом деле некоторые операции -- это целые программы со своими параметрами и аргументами и между операциями нет никакой связи. Минимальное число символов в названии операции 4, иначе трудно разделить все названия без потери смысла.

Мы начнем описание операций по принципу от простого к сложному. Полный список операций выглядит следующим образом


  fold  size  dele  copy  divi  fcat  find  repl rep2  line  list  edit  html  
  choo  edtf  tobm  tocm  tops  topng  w2jc  alph  mb64  modi  cdpj  edee

Все начинается с операций, которые обычно выполняет операционная система.

_____ FOLD _____
Эта операция переустанавливает рабочую папку программы относительно папки интерпретатора. Она выглядит так

 #f [op=fold; file=any; emp=;]

Имя папки задается параметром [file]. В имени можно использовать символ [/] для вложенных папок. После выполнения этой команды адрес рабочей папки меняется на всю последующую работу интерпретатора, то есть и после завершения выполнения текущей ACL программы. Единственный способ переопределить рабочую папку -- это снова выполнить данную команду с новым значением параметра [file]. В значении параметра [file] есть два особых случая. Если [file=null;], то будет установлена папка интерпретатора вместо папки с именем [null]. Точнее, в этом случае рабочая папка не используется. Имена файлов автоматически отсчитываются от рабочей папки интерпретатора. Но если в имени файла второй символ равен (:), то это правило нарушается и используется абсолютный адрес. Также если [file=oldf;] то будет восстановлена папка, которая была рабочей до последнего изменения. То есть папки с именами [null] и [oldf] нельзя задать никаким способом. Просто не используйте папки с такими именами.

В самом начале создания ACL если указанная рабочая папка не существовала, то она автоматически создавалась. В новых версиях используется дополнительный параметр [emp]. Если он = 0, то работает старый режим и папка создается. Но если он > 0 и папки с указанным именем не существует, то она и не создается, а значение параметра обнуляется. Задавая [emp=1;] и проверяя значение параметра после операции как элемент массива s(41) можно определить -- существует ли папка или нет. Если она не существует, то можно принять необходимые действия по предотвращению дальнейших операций. Это полезно в том случае, когда программа должна считывать файлы из папки, но папка не скопирована по тем или иным причинам, а создавать новую папку нежелательно.

Интересно, что проверить -- существует папка или нет -- таким способом можно даже те папки, которые находятся за пределами папки интерпретатора. Это также бывает полезно и иногда необходимо. Но папки за пределами интерпретатора нельзя использовать как рабочие папки. Необходимо задавать полное имя файла с символом (:) на второй позиции.


_____ SIZE _____
Эта операция просто определяет размер файла, имя которого задается параметром [file] и выглядит так.

 #f [op=size; file=any;]

Размер в байтах возвращается в s(1). Если s(1)=0, то нужно считать, что файла не существует.

_____ DELE _____
Эта операция уничтожает файл на диске. Она выглядит так

 #f [op=dele; file=any;]

Имя уничтожаемого файла указывает параметр [file].

_____ COPY _____
Эта команда чуть более сложная. Она создает новый файл с именем, которое определяет параметр [file], и с содержанием, которое является сложенными вместе содержаниями серии файлов, имена которых указывает серия аргументов FT (форматированного текста). Вот ее вид

 #f [op=copy; n=; file=newtotal;] file1.ext\E file2.ext\E ...

Описание FT дано в разделе 4. Другими словами, эта операция копирует несколько файлов в один. Число копируемых файлов указывает параметр [n]. При этом число аргументов может быть больше, но не может быть меньше, иначе фиксируется ошибка. Если в качестве аргументов указываются несуществующие файлы, то ошибка не фиксируется, просто указанные файлы игнорируются. Если все файлы не существуют, то создается нулевой файл.

_____ DIVI _____
Эта операция, наоборот, позволяет разделить файл на части и записать одну часть в новый файл. Вот ее вид

 #f [op=divi; file=; form=; b=; le=; n=; xsh=;] 

Имя исходного файла определяется параметром [file], имя нового файла определяется параметром [form] (formed). Исходный файл трактуется как матрица байтов, из которого вынимается подматрица. Для выполнения этой работы необходимо 4 параметра. Параметр [b] (begin) определяет число байтов, которые пропускаются с самого начала. После этого часть байтов длиной [le] (length) записываются и затем снова пропускаются байты длиной [xsh] (xshift). Такие le-xsh операции повторяются [n] (number) раз. Новый файл будет иметь ровно [le]*[n] байтов. Эта операция полезна, например, для выделения малой части большой картинки в новую картинку. Она также может быть полезна при работе с числовыми матрицами.

_____ FCAT _____
Эта операция возвращает каталог файлов в папке. Она выглядит так

 #f [op=fcat; file=any;]

Имя папки указывает параметр [file]. Оно должно быть указано полностью, начиная от папки интерпретатора, то есть рабочая папка не используется. Можно использовать папки за пределами папки интерпретатора указывая их с символом (:) во второй позиции. Каталог записывается в текстовый массив t() начиная с индекса, определяемого параметром s(3). После записи, как обычно, s(4) и s(5) указывают начало и длину проведенной записи. Если параметр [file] указывает не на папку, то возвращается s(5)=0. Список задается одной строкой, в которой имена файлов разделяются символом вертикальной черты ( | ).

_____ FIND _____
Эта операция выполняет поиск некоторой совокупности байтов внутри файла. Вот ее вид

 #f [op=find; b=; le=; file=any;]

Имя файла указывает параметр [file]. Последовательность байтов должна быть предварительно определена их значениями в целом массиве i(), причем индекс первого элемента определяет параметр [b] (begin), а число байтов определяет параметр [le] (length). Результат поиска возвращается в параметр s(2) как число повторений данной системы байтов. Важно помнить, что байты имеют значения от -128 до 127 в отличие от ASCII кодов. Например, код

 #d 2 i(11) 13 10
 #f [op=find; b=11; le=2; file=any;]

покажет число строк внутри файла в системах ДОС и Windows как значение s(2). Если s(2)=0, то этот файл либо имеет одну строку, либо он записан в системе UNIX-оидов, либо он числовой.

_____ REPL _____
Эта операция делает более сложную работу по сравнению с предыдущей операцией. Она находит все копии одной системы байтов и заменяет их на другую систему байтов. Вот ее вид

 #f [op=repl; b=; le=; mo=; file=any;]

Опять все байты, число которых равно значению параметра [le], должны быть заданы в массиве i(), начиная с индекса, определяемого параметром [b]. Но среди них [mo] первых байтов определяют систему, которая заменяется (модифицируется), а оставшиеся [le]-[mo] байтов определяют систему, которая будет записана вместо них. Новое содержание будет спасено в файле с тем же именем. Поэтому, если необходимо сохранить исходный файл, он должен быть предварительно скопирован с другим именем. Например, код

 #d 2 i(11) 44 46
 #f [op=repl; b=11; le=2; mo=1; file=some.txt;]

заменит все запятые в файле на точки.

_____ REP2 _____
Эта операция делает еще более сложную работу по сравнению с предыдущей операцией. Она находит все копии одной системы байтов и заменяет их на другую систему байтов. Но после каждой копии первой системы байтов она ищет вторую систему байтов и тоже ее заменяет другую вторую систему. Это выглядит примерно как то, что вам надо круглые скобки заменить на квадратные. Сначала надо заменить открывающую скобку, потом найти и заменить закрывающую скобку, которая отличается от открывающей. И так много раз. Разумеется, что это применимо только к специальным файлам, где много таких, условно говоря, скобок. Скобки могут иметь произвольную структуру и состоять из многих символов. Вот вид этой команды

 #f [op=rep2; b=; le=; mo=; tw=; th=; file=some.txt;]

Опять все байты, число которых равно сумме значений параметров [le] и [tw], должны быть заданы в массиве i(), начиная с индекса, определяемого параметром [b]. Но среди них [mo] первых байтов определяют систему, которая заменяется (модифицируется) в первой системе, а оставшиеся [le]-[mo] байтов определяют первую систему, которая будет записана вместо них. Далее [th] первых байтов определяют систему, которая заменяется (модифицируется) во второй системе, а оставшиеся [th]-[tw] байтов определяют вторую систему, которая будет записана вместо них. Новое содержание будет спасено в файле с тем же именем. Поэтому, если необходимо сохранить исходный файл, он должен быть предварительно скопирован с другим именем. Например, двойные круглые скобки на двойные квадратные заменит такой код

 # s(3)=1; #pr (([[))]]\E  #pas 8 t(1) i(1)
 #f [op=rep2; b=1; le=4; mo=2; tw=4; th=2; file=some.txt;]

так как параметры имеют номера подряд, то их можно определить через массив, соответственно альтернативный вид команды такой

 #d 5 s(9) 1 4 2 4 2 #f [op=rep2; file=some.txt;] 



_____ LINE _____
Эта операция читает из файла или записывает в файл строки текста. Она выглядит так

 #f [op=line; file=any; n=; b=; le=; emp=;]

Если параметр [n=-N;] отрицательное число, то прочитывается N-я строка текста в файле и ее содержание записывается в текстовый массив t() начиная с индекса, задаваемого параметром s(3). После операции s(4) и s(5), как обычно, показывают начало и размер записанного текста. А параметр s(3) автоматически сдвигается на s(4). Если N-й строки в файле нет, то параметр s(5) будет равен нулю. Наоборот, если параметр [n=N;] положительное число, то в файле записывается N-я строка, содержанием которой будет часть текстового массива t(), начиная с первого элемента, индекс которого определяется параметром [b] (begin), а число символов равно значению параметра [le] (length). Если файл имел больше, чем N, строк, то старое содержание N-ой строки будет изменено. Если в файле было меньше, чем N строк, он будет иметь ровно N строк. Строки между последней из бывших и N-й будут пустыми. Такой режим работы соотвествует старым версиям, когда параметр [emp=0;]. Если параметр [emp] > 0, например, [emp=1;], то при положительном [n=N;] в файле просто уничтожается N-ая строка. Параметр [emp] (enhanced mode parameter) позволяет реализовать дополнительные режимы работы команд, но он отсутствует в старых версиях, которые соответствуют нулевому значению. Поэтому не забывайте возвращать параметр [emp] в исходное состояние [emp=0;].

_____ LIST _____
Эта операция выполняет специальную работу. Вот ее вид

 #f [op=list; file=any; c=; b=; em=;]

Она прочитывает файл, имя которого указано параметром [file] и создает специальную строку текста в текcтовом массиве t(). В эту строку текста из файла берутся все символы начиная от начала и до символа, ASCII код которого определяется параметром [c] (code), включая и его самого. Затем она пропускает все символы после ASCII кода [c] до тех пор, пока не встретит символ с ASCII кодом [b] (begin), включая и его самого (то есть его тоже пропускает). Затем она снова берет все символы до первого появления ASCII кода [c] и так далее. Это выглядит так, как будто команда берет одну часть из двух частей записей в файл. Если запись имеет имя и тело, то команда может составить список имен. В результате число имен возвращается в параметр s(2), а сформированная строка записывается в текстовый массив t() начиная с индекса, определяемого, как обычно, параметром s(3). После операции номер первого записанного символа и число символов можно получить из параметров s(4) и s(5), аналогично другим похожим операциям. Такую работу, в принципе, можно сделать и с помощью других команд ACL, но эта операция работает намного быстрее, особенно для больших файлов. Как использовать эту операцию в реальной программе каждый программист решает сам.
В версиях после 22 марта 2023 года описанный выше режим работает при [em=0;]. Если параметр [em] не равен 0, то делается все наоборот. Сначала символы пропускаются, затем записываются и так далее. Иногда возникают ситуации, когда в файле записан заголовок или чужой текст. И необходимо его сначала пропустить. Могут быть и другие применения этого варианта.

Описываемые ниже операции реализуют намного более сложную работу, но эта работа делается полностью автоматически, так что использовать операции легко. А все особенности последующей работы программы можно изучить экспериментально, то есть уже в процессе работы с готовой программой.


_____ EDIT _____
Эта операция запускает готовый текстовый редактор для редактирования содержимого файла в отдельном (внешнем) окне. Вот ее вид

 #f [op=edit; c=; mo=; file=; b=; le=; em=; nx=; ny=; xs=; ys=;] FT

Имя файла определяется параметром [file]. Если файл отсутствует, то он будет создан. В этом случае редактор начинает с пустого текста. Отредактированное содержание будет записано в тот же файл, если [mo=1;] или не будет записано совсем, если [mo=0;]. Второй режим удобен для информационных файлов, содержание которых должно быть только показано и исправления нежелательны. При [mo=1;] файл перезаписывается автоматически при выходе из редактора по кнопке меню [Edit/Exit]. Если редактор запущен с записью измененного текста, а запись нежелательна, то можно закрыть редактор с помощью крестика в правом верхнем углу окна и записи не будет.

Меню редактора имеет кнопки в нескольких разделах: [Edit], [Convert], [Show], [Help]. Кнопки первого раздела имеют названия (Find), (Find Next), (Info), (Change font), (Wrap lines), (Exit). Кнопки (Find) и (Find Next) стандартные. Кнопка (Info) сообщает информацию о размере записанного текста, координатах курсора и абсолютном положении курсора. Кнопка (Change font) позволяет выбрать один из 5-ти логических фонтов и размер фонта. Эти значения хранятся в параметрах [fk] == s(27) (font kind) и [fs] == s(28) (font size). Как обычно, измененные значения параметров будут действовать до следующего определения, причем их можно изменить не только в окне редактора, а и в любом месте программы. Текущие значения этих параметров запоминаются в файле с именем (start.acl) в главной папке программы. Логические фонты реально отсутствуют. Интерпретатор проверяет наличие фонтов на компьютере и находит реальные фонты, близкие по свойствам заявленным логическим фонтам. Так что фонты можно просто проверить эмпирически и выбрать подходящий. Режим (Wrap lines) регулирует показ длинных строк, они либо загибаются на краю окна, либо нет. Повторный клик отменяет предыдущий режим на второй из двух возможных. Кнопка (Exit) имеет очевидное значение.

Меню [Convert] позволяет преобразовывать выделенный текст из русского в английский и наоборот, если он набран при неправильной раскладке клавиатуры, а также вообще устанавливать виртуальную раскладку клавиатуры независимо от операционной системы. Есть также преобразования от прописных букв к строчным и наоборот. Иногда это бывает очень полезно. Меню [Show] позволяет показывать прямо из редактора вэб-сайты на компьютере и в интернете, а также картинки на компьютере. Встроенное описание работы редактора помогает разобраться с его функциями в процессе работы.

Параметр [c] учитывается аналогично другим GUI операциям. А именно, если [c=0;], то программа продолжает выполнение других команд после открытия окна редактора. Первоначально это создавалось для автоматической презентации с помощью команды #robot, которая выполняла нажатие клавиш и операции с мышью вместо пользователя. Сейчас команда #robot заблокирована, но режим сохранен и иногда может быть полезен, однако использовать его нужно с осторожностью. Если [c=1;], то программа ждет, когда пользователь закроет окно и не разрешает переходить к другим окнам. Позиция курсора при входе в редактор определяется параметром s(1) без имени. После выхода из редактора этот же параметр содержит позицию курсора перед выходом. Позиция задается номером символа в тексте начиная от начала. Первый символ имеет индекс 0. Знание позиции курсора может быть использовано, например, при чтении книг, так как позволяет запомнить место остановки чтения, и в следующий раз начать прямо с этого места. Можно найти и другие применения.

Заголовком окна является полное имя файла с учетом текущей папки. Первооначально размеры окна редактора задавались стандартные, то есть 700*650, а само окно устанавливалось в центре экрана. Сейчас можно использовать параметр [em]=s(41) для установки дополнительных режимов. Как и в команде #input (см. главу 10) параметр [em] это двухразрядное целое число. Младший (правый) разряд имеет значения 0,1,2. При этом 0 - означает старый режим, то есть окно редактора помещается в центре экрана, 1 - новый режим, при котором окно редактора (левый верхний угол) сдвинуто из левого верхнего угла экрана на число пикселей, определяемых параметрами [xs] и [ys], 2 - специальный режим для проигрывателя, при котором сдвиг отсчитывается от левого верхнего угла главного окна программы. В основной программе главное окно устанавливается на весь экран и этот режим совпадает с предыдущим, но не совсем. Старший разряд параметра [em] имеет два значения 0,1. При этом 0 - опять означает старый режим, при котором окно редактора имеет стандартные размеры (см. выше), 1 - новый режим, при котором размеры окна равны (700+[nx])*(Y+[ny]), где значение Y определяется автоматически как вертикальный размер экрана - 100, а параметры [nx] и [ny] задают изменение таких стандартных размеров окна. Они могут быть как положительные, так и отрицательные. Это удобно при показе таблиц с заданной шириной и высотой.

Существует специальный режим работы команды, который задается через определение [file=here;]. В этом случае редактор работает с частью текстового массива t() вместо файла. Эта часть начинается с индекса, определяемого параметром [b] и имеет [le] символов. При этом параметр [mo] должен иметь значения -1 или -2. При [mo=-1;] результат редактирования не записывается (только чтение), а при [mo=-2;] отредактированный редактором текст записывается снова в текстовый массив, начиная с индекса, определяемого параметром s(3). Как обычно, после записи параметры s(4) и s(5) показывают начало и длину записанного текста. В этом случае заголовок окна задается аргументом в виде форматированного текста, причем аргумент обязателен и его отсутствие фиксируется как ошибка.

При выходе из редактора интерпретатор сообщает каким образом был сделан выход: по кнопке меню или кликом кнопки крестика на правом конце титульной строки. В первом случае переменная &=1, во втором &=2. Иногда эта информация может быть полезной для правильной организации работы ACL программы. Также параметр s(1) при входе в редактор задает начальную позицию курсора, которую легко заметить по выделению первого символа после позиции курсора. Это необходимо при поиске слов в файлах. А при выходе из редактора в этом же параметре записана позиция курсора на момент выхода.

Есть альтернативная операция EDTF, которая запускает другой редактор, смотри ниже в этом тексте.


_____ HTML _____
Эта операция дает возможность программисту показывать html-файлы, то есть запускать простой браузер, который был написан в самом начале разработки языка, то есть в середине 90-х годов прошлого века, и сейчас безнадежно устарел, но все же вполне работает с правильно отформатированными файлами. Вот его вид

 #f[op=html; file=any;] FT

Имя файла определяет параметр [file], но в данном случае имя должно быть указано полным относительно папки интерпретатора, рабочая папка не используется. Более того, можно указывать и абсолютный путь к файлу, включая имя диска, то есть, например, так [file=c:/first/second/file.htm;]. Гиперссылки внутри файла показываются в отдельном окне, которое полностью накладывается на предыдущее, поэтому для того, чтобы вернуться назад, нужно просто закрыть текущее окно, или переместить новое окно в другое место. Окна показываются в режиме диалога, то есть нет возможности продвинуться дальше по программе, пока не закроете окно. Размеры окна в этой операции заданы стандартным образом, но пользователь может их изменить по своему вкусу с помощью мышки (передвигая границы). Браузер выполнен в самом простом варианте и не содержит ни меню, ни иконок. Он предназначен, в основном, для показа специально приготовленных информационных текстов, вся навигация в которых может быть организована с помощью гиперссылок.

Так как размер текстовой строки параметра [file] ограничен 42 символами, то длинный путь к файлу записать не получится. Чтобы решить эту проблему введен специальный режим, а именно, можно записать [file=*N;], где N = 1, 2 или 3. В этом случае реальный путь к файлу считывается из аргумента FT, который обязан присутсвовать. При этом режим [file=*1;] используется для указания пути к файлу на локальном компьютере, а режим [file=*2;] используется для запуска страниц по адресу в интернете, но адрес надо указывать без заголовка "http://", так как заголовок подставляется автоматически. Естественно, во втором случае компьютер должен быть в сети. Однако сетевые файлы могут быть написаны так сложно, что браузер не сможет их обработать, поэтому я этой возможностью практически не пользуюсь. Хотя если записать html файлы самому и правильным образом, то все будет показано корректно. Режим [file=*3;] задает имя файла внутри jar-файла программы в папке [resources]. Это удобно при использовании программы в режиме спец-окна или проигрывателя, см. главу 25.


_____ CHOO _____
Эта операция запускает специальную программу, называемую на языке Java именем FileChooser. Она выглядит так

 #f [op=choo; mo=; file=;] FT

Эта операция дает возможность пользователю просмотреть полную файловую структуру используемого компьютера аналогично программам Менеджера файлов в разных операционнных системах. Просмотр начинается с папки, указанной параметром [file]. Параметр [file] может указывать или на любой файл, отсчитываемый от главной папки интерпретатора или сразу на папку. Для указания главной папки, то есть папки интерпретатора, можно использовать [file=start.acl;]. Программа имеет три варианта. Если [mo=0;], то используется общая форма и показываются все файлы. Кнопка [Select] позволяет выбрать файл. Полное имя выбранного файла, отсчитываемое от папки интерпретатора будет записано в текстовый массив t(), начиная с элемента, номер которого задает параметр s(3). После операции переменная [&] равна 2 если окно закрыто крестиком или выбрана кнопка [Cancel] или 1 если выбрана кнопка [OK]. В последнем случае, как обычно, s(4) и s(5) показывают начало и длину записи имени выбранного файла. Пользователь имеет возможность выбрать файл, находящийся за пределами папки интерпретатора. В этом случае операция вернет полное имя файла. В любом случае программист должен проявлять осторожность и проверять наличие выбранного файла с помощью операции [op=size;] в добавление к проверке значения переменной [&] и параметра s(5) прежде чем выполнять какую-либо операцию с выбранным файлом.

Если [mo=1;], то используется специальная форма, в которой показываются только графические файлы с расширениями gif, jpg, png и с предварительным просмотром. После выбора файла его имя будет передано так же как и описано выше. Выбранное имя программист может использовать по своему усмотрению, например показать картинку целиком. Третья возможность при [mo=2;] реализуется как в первом случае, но проводится отбор файлов по расширениям. То есть показываются не все файлы, а только те, у которых расширение совпадает с одним из указанного списка. Список расширений нужно задавать как аргумент, причем разные типы файлов разделяются знаком вертикальной черты, вот так txt|bat|mp3\E. Можно указывать только один тип файлов. Такая форма удобна при поиске файлов определенного типа, так как существенно уменьшает каталог и облегчает поиск нужного файла. Следует отметить, что в новых версиях JRE третий вариант перестал работать. Надо разбираться.


_____ EDTF _____
Эта операция во многом аналогична операции EDIT, так как она тоже редактирует текстовый файл. Отличие в том, что эта операция открывает внутренее окно, то есть такое окно, которое существует лишь в пределах окна главной программы. То есть это окно принадлежит не операционной системе, а только программе. Соответственно оно выглядит иначе и для него нет иконки в системной строке на экране. Системная строка обычно -- это нижняя строка. Вот как выглядит команда

 #f [op=edtf; mo=; file=; b=; le=; em=; xs=; ys=;] FT

В принципе окно редактора почти такое же, как и в операции EDIT, так как обе программы создавались первоначально одинаковыми. Но потом первая дорабатывалась, а вторая не использовалась в языке ACL и не менялась, или менялась иначе. Я укажу только на главные отличия. Самое главное отличие в том, что данный редактор не работает в модальном режиме. То есть если после его запуска есть еще другие команды в программе, то они сразу выполняются. Это значит, что данный редактор должен быть последним в программе, иначе он не получит фокус и не сможет работать.

При em=0 окно устанавливается стандартно, но если em=1, то можно указать сдвиги в параметрах xs и ys. Но данная программа может устанавливаться со сдвигом от левого верхнего угла окна главной программы. Что касается размеров, то они запоминаются при предыдущем вызове и снова ставятся такими же. Их можно изменить, двигая границы, и это снова запоминается. Параметров нет. В меню нет показа вэб-страниц и картинок. В остальном все точно так же. Например, параметр mo=1 указывает на запись изменений, а mo=0 изменения не записывает. Так же точно происходит при выходе из редактора кликом крестика в правом верхнем углу.

Главное преимущество этого редактора состоит в том, что он показывает тексты программ точно так же, как и сам интерпретатор в режиме отладки программы, так как это точно такой же редактор. У других редакторов могут быть другие фонты и при использовании символа tab расположение текста не совпадает с тем, какой был при отладке программы.

Следующие операции относятся к команде FILE по той причине, что они реально создают файлы. Но эти файлы имеют специальную природу. Эти операции могут пригодиться только в программах по обработке изображений. Поэтому читатели, которых не интересует эта тема, могут пропустить изучение этих операций. Тем более, что здесь используется специальная информация об изображениях. Как правило, эти операции используются в блоке с другими командами. После такого введения все же приступим к работе.


_____ TOBM _____
Эта операция конвертирует графические файлы с расширениями (gif, jpg, png) в byte-map файлы. Вот как она выглядит

 #f [op=tobm; file=; form=; dir=; n=; col=;]

Каждый байт byte-map файла описывает уровень серого от 0 до 255. Параметр [file] должен указывать имя графического файла, например, [file=one.jpg;]. Однако, если [file=here;], то картинка будет считана не из файла, а из оперативной памяти, в которой хранится массив картинок, как элемент с номером [n]. Такая картинка должна быть предварительно записана. В результате операции будет создан новый файл с именем, заданным параметром [form] как графический файл в новом формате. Этот формат нестандартный, некоторые его называют raw (необработанный). При этом, параметр [dir] (direction) определяет направление записи по вертикали. Если [dir=1;], то запись идет в направлении сверху вниз, обычном для графических файлов. Для любого другого значения, например [dir=0;], картинка записывается начиная с нижней строки вверх, как это делается во всех расчетных изображениях. Как обычно, элементы строк картинки записываются подряд. Ширина картинки возвращается в параметр s(12), а высота -- в параметр s(13). Цветные картинки преобразуются в серые по закону скалярного произведения с заданным цветом, номер которого в массиве цветов задает параметр [col]. Пусть этот цвет имеет компоненты R,G,B. Тогда цвет каждого пиксела приводит к уровню серого g по закону g=(r*R+g*G+b*B)/255), но внутри интервала (0,255). Такой способ позволяет применять цветные фильтры при конвертировании картинки, а также менять ее яркость. Информация о цветах будет описана ниже в разделе описания графики. Размер записанного файла в байтах равен числу пикселей в картинке.

_____ TOСM _____
Эта операция конвертирует графические файлы с расширениями (gif, jpg, png) в color-map файлы. Вот ее вид

 #f [op=tocm; file=; form=; dir=; n=;]

Каждые три байта color-map файла описывают уровень красного, зеленого и синего от 0 до 255 для одной точки рисунка (пиксела). Параметр [file] указывает имя графического файла, например, [file=one.jpg;]. Однако, если [file=here;], то картинка будет считана из оперативной памяти из массива картинок как элемент с номером [n]. Такая картинка должна быть предварительно записана. В результате будет создан новый файл с именем, заданным параметром [form] как графический файл в новом формате. При этом, параметр [dir] определяет направление записи по вертикали. Если [dir=1;], то запись идет в направлении сверху вниз, обычном для графических файлов. Для любого другого значения, например [dir=0;], картинка записывается начиная с нижней строки вверх, как это делается во всех расчетных изображениях. Как обычно, элементы строк картинки записываются подряд, три цвета на каждый элемент. Ширина картинки возвращается в параметр s(12), а высота в параметр s(13). Размер записанного файла в байтах равен утроенному числу пикселей в картинке.

_____ TOPS _____
Эта операция конвертирует графические файлы с расширениями (gif, jpg, png) в EPS файлы (encapsulated postscript file). Вот ее вид

 #f [op=tops; mo=; uni=; file=; form=; n=;]

Параметр [file] должен указывать имя графического файла, например, [file=one.jpg;]. Однако, если [file=here;], то картинка будет считана из оперативной памяти из массива картинок как элемент с номером [n]. Такая картинка должна быть предварительно записана. В результате операции будет создан новый файл с именем, заданным параметром [form] как графический файл в формате eps. Имя файла указывается вместе с расширением. Оно не обязано иметь расширение eps. При этом параметр [mo] должен быть 0, 1, 2, 3, 4 или 5. Значение 0 приводит к созданию черно-белого eps-файла, значение 2 - к фрагменту этого файла, который описывает картинку. Этот фрагмент можно использовать в команде #ps для создания комбинированной картинки. Значение 1 приводит к созданию цветного eps-файла, значение 3 - к фрагменту этого файла. Значения 4 или 5 описаны ниже. Другие значения приводят к ошибке. Параметр [uni] определяет дополнительно масштабирующий фактор для картинки в режимах [mo=0,1;], чтобы получить соответствие размеров eps-картинки на экране исходной картинке. Этот фактор равен отношению пиксела экрана к PS точке в единицах 0.0001. Например, пусть компьютер имеет 1024 пиксела на размере экрана 28.42 см. Когда используется GSview в режиме увеличения, показывающем бумагу формата A4 (595 точек) на размере экрана 26.4 см, отношение будет 0.6255. С этим значением GhostView показывает картинку точно также, как и vkACL. Однако, это соотношение может быть другим на других компьютерах. Каждый пользователь может определить отношение эмпирическим путем. В моем случае было [uni=6255;]. Иногда очень важно иметь соответствие каждого пиксела каждой точке экрана так как интерполяция приводит к артефактам.

Описанные операции я реализовал сам, используя законные команды языка постскрипт. И они делают eps файл, который нормально показывается программой GSview в комбинации с другим кодом только в том случае, если картинка стоит последней. Причина в том, что код записан без учета особенности компьютера считывать данные из файла кусками заданных размеров. Если за картинкой стоит какой-то код, то он может быть потерян при такой системе считывания. Соответственно невозможно комбинировать две eps картинки в одной, а также могут быть проблемы при использовании картинки в Латехе. Иногда все получается, но не всегда. По этой причине летом 2009 года я добавил две новые операции 4 и 5, код которых я заимствовал из чужой программы. При этом операция 4 делает полный eps файл, а операция 5 -- фрагмент. Этот код написан несколько другим способом, он более стабилен и не зависит от того, как считывается файл. Поэтому он всегда нормально работает при любых комбинациях постскрипт кода. Данный код всегда делает цветную картинку, соответственно размер файла получается большим. Но у него есть особенность. Если картинка имеет фиксированное число цветов меньше 256, то код использует карту цветов, что позволяет существенно сократить размеры eps файла. Понизить цветность картинки можно с помощью программы Fast Stone Viewer.

Здесь уместно отметить, что интерпретатор выполняет команду #pd, которая позволяет конвертировать большой спектр графических форматов в pdf-формат. Это также делается специальной библиотекой Java-классов, написанной другими авторами.


_____ TOPNG _____
Эта операция конвертирует графические картинки, записанные предварительно в памяти компьютера, в файл png-формата. Вот ее вид

 #f [op=topng; form=; n=;]

Запись картинок в память компьютера проводят графические команды #w #g #eg . Сами эти команды способны конвертировать картинки в файл jpg-формата. Но jpg-формат не всегда подходит для линейной графики. Файлы получаются неоправданно больших размеров, а линии окружены заметным грязным фоном, обусловленным алгоритмом jpeg-сжатия. В этом случае разумно спасать созданные картинки в память и затем конвертировать в png-файл с помощью указанной операции. Здесь параметр [form] указывает имя файла без расширения, который будет записан. Расширение всегда ".png". Параметр [n] указывает номер картинки, спасенной предварительно в памяти. Если картинка не существует, будет выдано сообщение об ошибке. Эта операция сделана для универсальности. Так как картинки создают несколько команд, то реализация в каждой команде записи в файлы разных форматов приводит к увеличению кода и сложной структуре параметров.

_____ w2JC _____
Эта операция имеет специальный характер, она может пригодиться при использовании программ, написанных на разных языках программирования. Она имеет очень простой вид

 #f [op=w2jc; file=;]

Дело в том, что файлы в компьютерном коде float (4 байта на одно реальное число) записываются в ACL программах так же, как в Java или в любой программе системы UNIX, то есть старшие байты слева, младшие справа. Однако в системе Windows принят обратный порядок - младшие байты слева. Поэтому для того, чтобы ACL программа могла правильно прочитать файл, записанный любой программой в системе Windows (например, написанной на фортране), необходимо переставить порядок байтов в каждом числе. Именно это и делает данная операция. Она прочитывает файл, переставляет в нем байты и новое содержание записывает на старое место. Повторное применение операции все возвращает на исходные позиции. Таким образом, эта операция позволяет как использовать результаты Windows программ в ACL, так и результатов ACL в Windows программах.

_____ ALPH _____
Эта операция тоже имеет специальный характер. У нее тоже несложный вид

 #f [op=alph;] FT FT

Она считывает текст из файла, полный путь к которому должен быть указан первым аргументом FT. Затем она упорядочивает все строки в тексте по алфавиту и новый текст записывает в файл, полный путь к которому указан вторым аргументом FT. Если оба файла находятся в той же папке, что и ACL программа, то полный путь определяется легко с помощью команд печати \M\H/имя файла. Если в начале каждой строки ставить номера, то операция упорядочивает строки по номерам. Если в каждой строке набито только одно слово, то операция упорядочивает слова по алфавиту.

_____ MB64 _____
Эта операция тоже имеет очень специальный характер. И использует код, который в Java указан как подлежащий удалению. Но его всегда можно будет использовать в старых версиях JRE. Вот ее вид.

 #f [op=mb64; mo=; file=; form=;]

Она кодирует содержимое любого файла, главным образом бинарного, например, файла картинки, в формат mime BASE 64, который используется в почтовых машинах для передачи электронных писем. Этот же формат используется в электронных книгах формата fb2 для кодирования картинок. Эта операция, как раз, и была разработана для создания электронных книг. У нее есть две модификации. При mo=1; файл с картинкой кодируется в формат mime, а при mo=2; файл в формате mime снова кодируется картинкой. С точки зрения почты первая модификация кодирует почтовую передачу, а вторая возвращает информацию в исходное состояние. В частности вторую операцию можно использовать, чтобы вынимать картинки из электронных книг и возвращать им исходный вид. Но главной все же является первая операция, позволяющая создавать электронные книги.

Параметр file должен содержать имя файла -- источника. Имя можно задавать как относительно рабочей папки, так и полное имя на компьютере в любой папке. Параметр form указывает имя вновь создаваемого файла после кодировки. Но в нем достаточно указать, только последние символы в имени, которые не совпадают с символами имени файла источника. Обычно предполагается, что вновь создаваемый файл находится в той же папке, и с тем же именем, только расширение меняется. При этом такой способ задания имени позволяет не писать слишком много символов.


_____ MODI _____
Эта операция появилась 28 апреля 2023 года. Она дает информацию о времени последнего изменения файла. Вот ее вид

 #f [op=modi; file=;]

В языке Java эта операция выдает время в целую переменную длиной 8 байтов в миллисекундах от начала 1970 года. Но в ACL нет таких переменных. По этой причине информация выдается в два целых числа -- параметры s(1) и s(2). При этом в s(2) выдается целое число декад, то есть отрезков времени в полных 10 дней, а в s(1) -- остаток после вычитания произведения s(2) на время одной декады. Эта информация умещается в целые числа длиной 4 байта. Далее ее можно преобразовать в другие формы по желанию программиста.

_____ CDPJ _____
Эта операция появилась 30 июня 2020-го года после того, как я научился программировать на Питоне. Вот ее вид

 #f [op=cdpj; file=; form=;]

На Питоне и в системе Виндовс данные в компьютерном коде спасаются в файлы с расширением npy. Они имеют шапку из 128 байтов и записывают числа в формате double, как он называется в Java и в ACL, но с порядком байтов как в Виндовс, то есть младшие вперед. Соответственно, чтобы прочитать такие числа ACL программой, необходимо отрезать шапку и перевернуть порядок у каждых 8 байтов. Как раз это и делает данная операция. Параметр file должен указывать имя файла, записанного Питоном, параметр form указывает имя файла, который создает данная операция. Он содержит ту же информацию, но в формате, который ACL способен прочитать как данные типа double.

_____ EDEE _____
Данная операция не относится к командам ACL, но она очень близка к операции #f [op=edit;] и по этой причине ее описание разумно сделать здесь. Она тоже редактирует текстовый файл, но для этого используется очень большой редактор, который первоначально был сделан как самостоятельная Java программа и он запускается специальным образом. Но со временем эта программа научилась обрабатывать некоторые переменные и параметры языка ACL, так что ее можно было оформить как операцию. Но это не сделано и ее запуск выполняется несколько другим способом, а именно,

 # &=0; #pr Полный путь к файлу\E  #e [n=1; em=1; c=1;] _\09 

Итак, программа редактирует файл, полный путь к которому относительно папки интерпретатора (или совсем полный) нужно напечатать предварительно. У нее есть свое собственное меню и свое собственное описание. Она реагирует на параметры. При указанном способе работы [n=1; em=1;] обязательно. Параметр с может иметь все значения, которые он обычно принимает. При [c=1;] редактор останавливает работу ACL программы, а при [c=0;] он ее не останавливает, то есть открывает свое окно и программа продолжает работу, в частности может открыть второй редактор. При [c=1;] программа может реагировать на значение переменной &. Если редактор был закрыт кликом крестика в правом верхнем углу, то переменная не меняет свое значение. А если по клавише [Esc] то она принимает значение 1. Исходно значение & есть 0, но для того, чтобы узнать как был сделан выход из редактора, разумно обнулять переменную перед вызовом редактора.