9. НАЧАЛО СОЗИДАНИЯ,
или
Простой редактор текста EDIT
  Verba dolant, Scripta manent
Слова улетают, написанное остается

       — Ну, вот, Алеша,— говорю я, когда мы в очередной раз пришли в машинный зал,— мы и добрались до заветной цели нашего путешествия. Сегодня мы займемся созданием текста.
       — Наконец-то,— с удовлетворением заметил Алеша,— а то мы только и знаем, что перекидываем с места на место кем-то созданные файлы, а сами создавать не умеем.
       — Ну, это ты брось,— говорю я,— один способ создавать текстовые файлы ты уже знаешь.
       — Это с помощью ключа /OUTPUT для программ DIR и DUMP. Так это неинтересно. Я хочу написать что-нибудь свое.
       — Значит, ты не все понял в прошлый раз,— говорю я,— вспомни, что мы говорили про команду TYPE?
       — Что эта команда введена для удобства пользователя,— вспоминает Алеша,— она копирует текстовые файлы на экран терминала и, в сущности, представляет собой команду:

       COPY/ASCII DEV:FILE.LST TT:

       — Правильно, Алеша. Но ты мог бы догадаться, что терминал состоит из двух устройств: выходного — это экран дисплея — и входного — это клавиатура.
       Поэтому операция копирования может быть выполнена и в обратную сторону, т.е. с клавиатуры в файл.
       — Вот здорово,— загорелся Алеша,— это нужно попробовать:

  +---------------
  !  .COPY TT: DX1:PROBA.LST<ВК>
  !  -
  !            Files copied
  !            ------------
  !  TT:            to  DX1:PROBA .LST
  !  ---------------------------------
  !  ^ЭТОТ ГЛУПЫЙ ТЕКСТ ДЛЯ ПРОБЫ<ВК>
  !  -
  !  НАПИСАЛ АЛЕША<ВК>
  !  ^Z
  !  .^
  !

       — А закончить текст нужно символом CTRL/Z,— сказал Алеша,— это я помню. И сразу можно его посмотреть.

  +---------------
  !  .COPY DX1:PROBA.LST TT:<ВК>
  !  -
  !         Files copied
  !         ------------
  !  DX1:PROBA .LST  to  TT:
  !  -----------------------
  !  ЭТОТ ГЛУПЫЙ ТЕКСТ ДЛЯ ПРОБЫ
  !  ---------------------------
  !  НАПИСАЛ АЛЕША
  !  -------------
  !  .^
  !

       — И заметь, Алеша,— говорю я,— что здесь нет никакого изобретения, и эта возможность просто вытекает из логической основы операции копирования.
       Более того, так как терминал состоит из двух устройств, мы можем скопировать текст с клавиатуры на экран без обработки его клавиатурным монитором. Это бывает нужно, например, для установки некоторых режимов терминалов VT52, VT100 и др. Например, чтобы на терминале VT100 (он эмулируется на "Электронике-85") изображения набираемых символов было инверсное, т.е темные буквы на светлом фоне, нужно послать на экран следующую последовательность символов:

  +---------------
  !  .COPY TT: TT:<ВК>
  !  -
  !            Files copied
  !            ------------
  !  TT:            to  TT:
  !  ----------------------
  !  ^<ESC>[7m^Z
  !  -
  !  .^
  !

       где символ "ESC" на зарубежных терминалах имеет специальную клавишу, на отечественных ей соответствует клавиша <АР2>. Кроме того, его можно получить одновременным нажатием клавиш CTRL/[.
       Простота такого способа является большим достоинством, но оно омрачается двумя недостатками — мелким и крупным. Мелкий недостаток состоит в том, что, хотя этот способ можно в самом деле использовать для получения текстового файла, как правило в аварийных или нештатных ситуациях, но помимо этого он мало на что пригоден. Однако крупный недостаток состоит в том, что мы не в состоянии каким-либо образом изменить, отредактировать уже введенный текст.
       Вообще удивительно, как мы до сих пор справлялись с ошибками при вводе команд. Ведь первый случай создания текста — это ввод командной строки. Пусть текст только на экране и в буфере монитора, но он должен быть без ошибок.
       — А я давно догадался,— довольный собой сказал Алеша.
       Если мы внимательно посмотрим на клавиатуру, то увидим либо клавишу <ЗБ> ("Забой" на терминалах 15ИЭ-00-013), или <DEL>, <RUBOUT> на зарубежных терминалах, или что-нибудь подобное. Основная функция этой клавиши — удалить последний введенный символ.
       — Ты прав, Алеша,— добавляю я,— однако сам терминал удалять символ не умеет. Его удаляет программа, принимающая символы с клавиатуры. И в зависимости от установленного режима она может вести себя двояким образом.
       Для начала вспомним историю. Когда не было дисплеев у первых мини-ЭВМ, в качестве терминала использовалась пишущая машинка или телетайп, которая была установлена на выступающей подставке. Такой выступ в строительном деле называется — консоль. Системный терминал также стали называть системной консолью. И, несмотря на то, что в последствии они стали устанавливаться отдельно, как, например, LA36 или LA120 (а для микро-ЭВМ "Электроника-60" — пишущая машинка "Консул"), название сохранилось. Для таких терминалов удаление символа на бумаге технически невозможно. А для того, чтобы показать, что в памяти этот символ удален, на бумаге печатается знак "\" и символы, которые были удалены. Например:

       .DABE\EB\TE

в результате получится

       .DATE

но иногда легче сразу удалить всю введенную строку и набрать ее заново. Для этого используется служебный символ "CTRL/U".
       Для тех случаев, когда система знает, что мы используем дисплей, клавиша <ЗБ> или <DEL> будет работать, как ей полагается, т.е. в действительности и в памяти, и на экране будет удаляться последний введенный символ.
       И всегда остается силовой прием — вызвать KMON снова, нажав клавишы "CTRL/C". На экране появится точка, и все можно начинать сначала.

 

9.1. Как мы пишем,
или
Что такое текст

       Вот теперь, когда мы имеем средства, хотя и примитивные, но все же достаточные для создания текста, можно поговорить, что такое текст.
       — А что о нем говорить,— не понимает Алеша,— берешь лист бумаги и пишешь, где хочешь.
       — Это ты так говоришь, потому что не отдаешь себе отчета в тех командах, которые твой мозг посылает руке. И даже при этом ты все-таки пишешь последовательно букву за буквой, слово за словом. А если писать в произвольном порядке — одну букву здесь, а другую там, то это уже будет не текст, а картина. Кроме того, читаешь ты текст тоже последовательно. Еще никто не придумал устройство, которое способно распознать сразу такой сложный образ, как страница текста.
       И чтобы как-то отделить твой мозг от исполняющего органа — руки, давай посмотрим, как ты пишешь на обычной механической пишущей машинке.
       — Я нажимаю на клавишу, которая соответствует нужному символу,— перечисляет Алеша, для которого эти действия привычны,— рычаг с литерой ударяет по бумаге и после его опускания каретка передвигается на одну позицию влево.
       — Вот видишь,— говорю я,— ты уже назвал одну отличительную черту текста — позицию символа, — каждый символ в тексте имеет свою позицию в строке. А как, например, начать новую строку?
       — В таком случае я либо сам возвращаю каретку в начальное, крайнее правое положение, либо пользуюсь рычагом возврата каретки, который сблокирован с механизмом перевода валика, т.е. строки.
       — Итак,— говорю я,— у тебя уже появились знакомые символы "Возврат Каретки" и "Перевод Строки". Кстати, заметь, что символ "Пробел" теперь имеет такое же значение, как и любой другой символ. Он так же имеет специальную клавишу и позицию в тексте.
       А теперь посмотрим, как это отражается в системе. Набери в файл какой-нибудь короткий текст и с помощью программы DUMP посмотри, как он будет представлен в памяти системы.
       — Я недавно в словаре юного книголюба прочитал четверостишье Пушкина,— вспоминает Алеша,— вот его и наберу в файл.

  +---------------
  !  .COPY TT: DX1:VERSE.TXT<ВК>
  !  -
  !  ^ВОДЫ ГЛУБОКИЕ<ВК>
  !  ПЛАВНО ТЕКУТ<ВК>
  !  ЛЮДИ ПРЕМУДРЫЕ<ВК>
  !  ТИХО ЖИВУТ<ВК>
  !  А.ПУШКИН<ВК>
  !  ^Z
  !

       — Сразу посмотрим, что у нас получилось,— сказал Алеша,— а заодно распечатаем дамп этого файла. Углом с отступом мы будем показывать угол листа бумаги.

  -------+-------
         !ВОДЫ ГЛУБОКИЕ
         !ПЛАВНО ТЕКУТ
         !ЛЮДИ ПРЕМУДРЫЕ
         !ТИХО ЖИВУТ
         !А.ПУШКИН
 
 
  167 157 144 171 040 147 154 165 142 157 153 151 145 015 012 160
  В   О   Д   Ы       Г   Л   У   Б   О   К   И   Е   .   .   П
  154 141 167 156 157 040 164 145 153 165 164 015 012 154 140 144
  Л   А   В   Н   О       Т   Е   К   У   Т   .   .   Л   Ю   Д
  151 040 160 162 145 155 165 144 162 171 145 015 012 164 151 150
  И       П   Р   Е   М   У   Д   Р   Ы   Е   .   .   Т   И   Х
  157 040 166 151 167 165 164 015 012 141 056 160 165 173 153 151
  О       Ж   И   В   У   Т   .   .   А   .   П   У   Ш   К   И
  156 015 012 000 000 000 000 000 000 000 000 000 000 000 000 000
  Н   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .

       Мы не будем приводить адреса каждого блока (тем более что он один). Нам нужно только соответствие символа и его восьмеричного кода.
       — А теперь,— говорю я Алеше,— расставь эти коды так, как выглядит твое стихотворение на бумаге.
       — Тогда,— отвечает он,— я буду ориентироваться на начала строк стихотворения, так как они начинаются от края бумаги.

  167 157 144 171 040 147 154 165 142 157 153 151 145 015 012
   В   О   Д   Ы       Г   Л   У   Б   О   К   И   Е  """+"""
   +-----------------------------------------------------+
   V
  160 154 141 167 156 157 040 164 145 153 165 164 015 012
   П   Л   А   В   Н   О       Т   Е   К   У   Т  """+"""
   +-------------------------------------------------+
   V
  154 140 144 151 040 160 162 145 155 165 144 162 171 145 015 012
   Л   Ю   Д   И       П   Р   Е   М   У   Д   Р   Ы   Е  """+"""
   +---------------------------------------------------------+
   V
  164 151 150 157 040 166 151 167 165 164 015 012
   Т   И   Х   О       Ж   И   В   У   Т  """+"""
   +-----------------------------------------+
   V
  141 056 160 165 173 153 151 156 015 012 000
   А   .   П   У   Ш   К   И    Н """+"""  .
  <----------------------------------+

       Сразу видно,— расставив коды и символы, говорит Алеша,— что любая строка заканчивается кодами 015 и 012.
       — Совершенно верно, и если я тебе подскажу, что код 015 соответствует символу "ВК", а код 012 соответствует символу "ПС", что ты можешь сказать?
       — Тогда мы должны ввести понятие текущей позиции в тексте. Если вернуться к пишущей машинке, то это позиция, на которой будет напечатан (введен) следующий символ. В таком случае возврат каретки ("ВК") соответствует установлению текущей позиции в первую колонку на строке. Но строка при этом осталась та же и, если мы начнем печатать, то вновь введенные символы наложатся на те, которые были напечатаны на бумаге. И чтобы этого не произошло, вслед за "ВК" вводится символ перевода строки "ПС", который передвигает валик на одну строку, и номер текущей позиции увеличивается на единицу. Именно это обстоятельство я показал на рисунке, подчеркнув коды 015,012 и обозначив стрелкой их действие.
       — Молодец, Алеша,— говорю я,— в понятии ТЕКСТ есть несколько "мелочей", которые пользователей ставят в тупик, и ты объяснил одну из них. Большинство функций команд редактора связано с перемещающимся указателем текущего положения, который обычно расположен между ближайшим символом, над которым производится операция, и следующим символом в буфере. Важно понимать, что этот указатель находится между двумя символами, но не над и не под символом. В начале операции редактирования указатель текущего положения предшествует первому символу буфера, хотя это и не отображается на терминале. В любое время в течение процедуры редактирования необходимо представлять указатель как текущую позицию редактора в тексте. Указатель перемещается во время операций редактирования в зависимости от самой выполняемой операции. При этом символы "ВК", "ПС", "ГТ", "ПФ" воспринимаются как обычные одиночные символы пользователя. Но в набранном тобой тексте есть одна "некрасивость". Все слова прижаты к началу строк, а везде принято фамилию автора печатать ближе к правому краю бумаги или хотя бы под концом строк стихотворения.
       — Я согласен,— отвечает Алеша.— Чтобы это сделать, есть самый простой способ — между кодами 015,012 и последующими символами "А.ПУШКИН" вставить символы "Пробел". Каждый из них занимает ровно одну позицию, а на бумаге не печатается, и его код мы уже видели в нашем тексте — это 040. Но для этого нужно использовать редактор текста, либо, если пользоваться нашим примитивным способом, набрать ВЕСЬ текст снова.
       Ну что же, начнем работать с редактором.
       История редактора текстовых файлов EDIT восходит еще к мини-ЭВМ PDP-8 и ее операционной системе OS-8. Тщательно определенный набор команд привел к тому, что практически все время EDIT просуществовал без изменений. За такое долгое время эксплуатации (только в RT-11 уже 17 лет) большинство ошибок в нем было выявлено. Ограниченные возможности компенсируются высокой надежностью и неприхотливостью к параметрам аппаратуры. Можно сказать, что на редакторе текста EDIT висит вывеска "Проверено! Мин нет!".
       Простота концепции EDITа привлекла и Гарри Кэлдела. Текстовой редактор ED из операционной системы CP/M отличается от EDITа из RT-11 лишь несколькими мелочами, не существенными для пользователя.
       Исторически сложилось так, что при проектировании редактора EDIT существовали только посимвольные печатающие устройства — телетайпы (отечественный аналог — пишущая машинка "Консул", поставляемая с "Электроника-60") — и графические векторные дисплеи VT11 (отечественный аналог СМ-7300 или ЭПГ СМ). Поэтому редактор позволял выполнять на телетайпах и пишущих машинка построчное редактирование, а на графических терминалах — непосредственное редактирование, показывая на экране целый кусок текста в 20 строк.
       Графический терминал VT11 уже стал исторической редкостью, поэтому работу с ним мы описывать не будем. Пишущие машинки тоже канули в лету, но именно ограниченность возможностей пишущей машинки позволяет редактору EDIT работать с любыми терминалами, не обращая внимания на различного рода изобретения и усовершенствования.
       Так как редактирование происходит в одной строке и необходимо одними и теми же средствами вводить команды для редактора и сам текст пользователя, то основная трудность состоит в том, чтобы однозначно разделить команды редактора и текст пользователя.
       Основная концепция текстового редактора EDIT заключена в следующем: выбран специальный символ "ESCape", который в обычном тексте пользователя встречаться не может, в силу чего его можно использовать как разделитель команд. Два символа "ESC", введенных подряд, инициируют обработку всего набора команд, введенных оператором.
       В результате всю командную строку в общем виде можно изобразить следующим образом:

    *команда-1<ESC>команда-2<ESC>команда-3<ESC><ESC>

Примечание. На терминале редактор EDIT отображает символ "ESC" с помощью символа "DOLLARS" — $, поэтому нужно быть внимательным, чтобы не спутать истинный знак доллара с отображением символа "ESC".
       В дальнейшем символ "ESC" стал применяться для управления отдельными функциями терминалов и принтеров и в принципе в тексте пользователя встречаться может. Есть также редакторы текста, например KED, позволяющие вставлять этот символ в текст пользователя. Конец примечания.

       В командах различают три элемента, не все из которых могут присутствовать, но если присутствуют, то должны быть введены в следующей последовательности.
       — Числовой аргумент
       — Имя команды
       — Текстовой аргумент
       Причем, если команда не требует текстового аргумента, то использование символа "ESC" для разделения команд необязательно.
       ЧИСЛОВОЙ АРГУМЕНТ может представлять собой десятичное число в диапазоне от —16383. до +16383. или символы "/", "=". При этом знак "+" может опускаться, а отсутствие аргумента предполагает значение 1 (или -1, если перед командой стоит знак "-").
       ИМЯ КОМАНДЫ состоит из одного или двух латинских символов верхнего регистра. Редактор в командном режиме сам переводит символы нижнего регистра в символы верхнего.
       ТЕКСТОВОЙ АРГУМЕНТ — строка или несколько строк текста пользователя, которые могут включать символы "ВК", "ПС", "ПФ", "ГТ" и т.п. Так как имя команды представляет собой обычный символ, то в случае пропуска имени команды в ее качестве используется первый символ текста.
       — В таком случае,— говорит Алеша,— синтаксис команды можно описать следующим образом:

       Команда:=[N]<ИМЯ>[текст]$

       И на все определение у нас ушло меньше странички.
       — Почти,— говорю я,— есть еще маленькое дополнение.
       Команду или последовательность команд можно выполнить несколько раз, заключив всю последовательность в угловые скобки, и указав перед ними число повторений. Вот так:

    3<Команда-1$5<Команда-2$Команда-3$>>$$

       Редактор позволяет использовать до 20 уровней скобок и перед выполнением команд проверяет корректность использования скобок.
       — Вот и все, что нужно знать о синтаксисе редактора EDIT,— говорю я,— а теперь давай исправляй свой текст.
       — Мы все время говорили, что редактирование текстов занимает в работе пользователя наибольшую часть,— начал Алеша,— поэтому логично будет, если команда, вызывающая редактор текста, будет называться EDIT, и для редактирования текста достаточно набрать команду

  +---------------
  !  .EDIT DX1:VERSE.TXT<ВК>
  !  -
  !  *^
  !

       — Ты совершенно прав, но начиная с версии 5.2 этой командой по умолчанию вызывается более мощный и современный редактор KED. Если ты хочешь, чтобы в современных версиях вызывался по умолчанию редактор EDIT, то нужно об этом сказать системе.
       — Либо воспользоваться явным способом,— говорит Алеша,— набрав команду

  +---------------
  !  .RUN SY:EDIT DX1:VERSE.TXT<ВК>
  !  -
  !  *^
  !

       — Правильно,— говорю я,— в любом случае после вызова редактора в начале строки будет напечатана звездочка, которая говорит о том, что редактор готов к приему команд.
       — И теперь можно редактировать текст,— торопится Алеша.
       — А текста еще нет в памяти, поэтому редактировать нечего. А для начала сразу разберем процессы, которые происходят при работе редактора.
       Во-первых, какие файлы участвуют в данной операции? Общее правило фирмы DEC, которое выполняется и в других ее системах,— ничего не изменять в исходном файле. Поэтому редактор сразу открывает второй файл, который является выходным, и все изменения записывает в него. После окончания работы и закрытия выходного файла входной файл переименовывается в тип .BAK (запасной), а выходной файл наследует имя и тип входного. Это можно изобразить следующим образом.

  +---------+    +------------------------+    +'''''''''+
  !VERSE.TXT!===>! **** ****   ***  ***** !===>!VERSE.TXT!
  +---------+    ! *     *  *   *     *   !    +.........+
      V          ! ***   *  *   *     *   !         V
  +---------+    ! *     *  *   *     *   !    +---------+
  !VERSE.BAK!    ! **** ****   ***    *   !    !VERSE.TXT!
  +---------+    +------------------------+    +---------+

       Такая стратегия позволяет защититься от аварий и ошибок самого пользователя. И из нее вытекает два момента.
       Мы можем явно указать спецификацию выходного файла, используя ключ /OUTPUT, так же, как мы это делали в программах DIR или DUMP. В этом случае редактор не будет переименовывать входной файл в тип .BAK.
       Кроме того, мы можем указать, что не будем вносить изменения, т.е. использовать входной файл только для просмотра. Этот весьма строгий ключ /INSPECT стоит применять всегда, когда редактирование не предполагается.
       — А если у нас еще нет файла для редактирования,— догадался Алеша,— мы, наверное, должны использовать ключ /CREATE — создать,— и редактор создаст запись в каталоге и зарезервирует на диске свободное место.
       — Совершенно верно,— говорю я,— но все эти команды мы делали из клавиатурного монитора, а иногда имеет смысл делать эти операции, находясь в редакторе.
       — И если мы введем команду

  +--------------
  !  .RUN SY:EDIT<ВК>
  !  -
  !  *^
  !

       — спрашивает Алеша,— редактор позволит выполнить те же действия?
       — И не только позволит,— отвечаю я,— но и явно разъяснит, что он делает. Кроме того, все это время сохраняется текстовой буфер редактора, что позволяет переносить достаточно большие куски текста из одного файла в другой.
       Первое, что нужно сделать, — это открыть файл для чтения и подготовить его для редактирования. Команда Edit Read сокращенно записывается следующим образом:

  +---------------
  !  *ERdev:filnam.typ$$
  !  -
  !  *^
  !

       Команда не влияет на содержимое буферов, а только устанавливает связь редактора с файлом. Так как одновременно может быть открыт только один файл для чтения, то команда ER закрывает предыдущий файл, если он был открыт.
       — И наверное,— говорит Алеша,— если мы входим в EDIT из клавиатурного монитора по команде EDIT/INSPECT или EDIT/OUTPUT, команда Edit Read автоматически выполняется для файла, названного в команде EDIT.
       — Правильно,— подтверждаю я,— но нам необходимо и записывать файл.
       — По аналогии,— подхватывает Алеша,— команда должна быть Edit Write и записывается следующим образом.

  +--------------
  !  *EWdev:filnam.typ[nblk]$$
  !  -
  !  *^

       — Да, команда EW открывает файл,— продолжаю я,— для вывода вновь созданного или отредактированного текста. Однако ни выходной текст, ни содержимое буферов не изменяется. И так как для вывода может быть открыт только один файл, EDIT закрывает уже открытый файл и сохраняет сделанные в нем изменения. Десятичное число, указанное в квадратных скобках (они являются частью спецификации файла и должны вводиться пользователем), определяет длину выходного файла.
       — Или, если мы будем работать с клавиатурным монитором,— добавляет Алеша,— это соответствует ключу /ALLOCATE:nblk. И также если мы войдем в EDIT из монитора по команде EDIT/CREATE или EDIT/OUTPUT, команда EW автоматически выполняется для файла, указанного с ключем /OUTPUT или в команде EDIT.
       — А какая же команда,— спрашивает Алеша,— будет соответствовать обычной команде монитора EDIT, т.е. если я в клавиатурном мониторе даю команду:

  +---------------
  !  .EDIT DX1:VERSE.TXT<ВК>
  !  -
  !

       — То,— отвечаю я,— в редакторе это эквивалентно следующим действиям.

  +---------------
  !  .RUN SY:EDIT<ВК>
  !  -
  !  *EBDX1:VERSE.TXT[nblk]$$
  !  -

       Команда Edit Backup также резервирует нужное количество блоков, как и команда Edit Write. Кроме того, по завершению редактирования переименовывает входной файл в тип .BAK.
       И наконец, мы можем просто закрыть выходной файл командой End File (EF), не прекращая работы с входным.
       — Но все наши долгие разговоры,— говорит Алеша,— касались только того, как указать редактору спецификацию файла и способ работы с ним. А ведь нам нужно еще прочитать наш файл.
       — И не только прочитать, но и записать,— отвечаю я.

 

9.2. Команды ввода/вывода

       — Я думаю, тебе понятно,— продолжаю я,— что редактор не может прочитать в память весь файл, потому что он может быть очень большой. Поэтому редактор читает файл страницами.
       — Это соответствует странице на бумаге?— спрашивает Алеша.
       — И да, и нет,— отвечаю я,— дело в том, что здесь еще нет четкого определения страницы. Чтение страницы прекращается либо если встретится символ перевода формата "ПФ", либо если заполнен внутренний текстовой буфер, что примерно соответствует странице, хотя и разной длины, так как его размер зависит от объема свободной памяти в системе.
       — И наверное,— заметил Алеша,— чтение может прекратиться, если редактор встретил конец входного файла.
       — Правильно!
       — Но тогда у нас,— не унимается Алеша,— должны быть средства для записи буфера в файл.
       — Конечно,— отвечаю я,— но запись уже происходит либо по строкам, т.е. ты указываешь сколько строк нужно записать в файл; либо целиком текстовой буфер, в том объеме, на сколько он заполнен. При этом следует учесть, что текстовой буфер освобождается на объем выведенного в файл текста.
       — Значит,— говорит Алеша,— весь процесс редактирования представляет собой поочередное чтение текста из входного файла в буфер и запись отредактированного текста из буфера в выходной файл.
       — И для того чтобы упростить этот процесс,— добавляю я,— была введена комбинированная команда, которая сначала записывает текстовой буфер в выходной файл, очищает его и читает в него следующую страницу текста из входного файла.
       И так как ты у нас знаток английского языка,— предлагаю я Алеше,— то назови названия этих трех команд.
       — Пожалуйста,— не смущаясь отвечает Алеша,— команда чтения страницы из входного файла так и будет называться Read — чтение — и мы сократим ее до одной буквы R.
       Команда записи текста в выходной файл будет также прямым переводом — Write — писать, — и также мы сократим ее до одной буквы W. Но она уже должна иметь числовой аргумент, который может принимать следующие значения:

+N
       — записывает N строк текста, начиная от указателя и кончая концом N-ой строки;

-N
       — записывает N строк текста, начиная с первого символа на -N строке и кончая указателем;

0
       — записывает в выходной файл текущую строку от начала до указателя;

/
       — записывает в выходной файл текст от указателя до конца буфера.

       И наконец, следущая страница читается командой Next, также сокращенной до одной буквы N. Так как мы можем писать в выходной буфер только в одном направлении — вперед, то числовой аргумент может быть только положительный и означает, сколько страниц нужно переписать из входного файла в выходной. Команда Next с числовым аргументом — это удобный и быстрый способ добраться до известной страницы текста, если в начальных страницах нет необходимости вносить изменения.
       — Молодец Алеша,— завершаю я наш разговор,— в заключение нужно только сказать о команде EXit, которая заканчивает сеанс редактирования. Команда EX последовательно выполняет следующие действия:
       — записывает текстовый буфер в файл;
       — переносит остаток входного файла в выходной файл;
       — закрывает все входные и выходные файлы;
       — переименовывает входной файл в тип .BAK, если команда EB была в действии;
       — возвращает управление клавиатурному монитору.
       Аргументов у этой команды нет, поэтому если напечатать:

  +---------------
  !  *EX$$
  !  -
  !  .^
  !

то все действия, необходимые для завершения сеанса редактирования, будут выполнены.

 

9.3. Начало редактирования

       — И теперь можно приступать к редактированию,— сказал Алеша, набирая команду

  +---------------
  !  .EDIT DX1:VERSE.TXT<ВК>
  !  -
  !  *R$$
  !  -
  !  *

       И никакого текста на экране,- удивленно сказал Алеша.
       — А чему ты удивляешься,— говорю я,— мы говорили, что редактор построчный и предназначен для пишущих машинок, поэтому для того, чтобы увидеть текст, нужно дать ему команду.
       — Распечатки программ называются листингами,— говорит Алеша,— и так как раньше ЭВМ использовались в основном программистами, то возможно, что команда, распечатывающая текст, будет называться List, и сократив ее до одной буквы, попробуем:

  +---------------
  !  *R$$
  !  -
  !  *L$$
  !  -
  !  ВОДЫ ГЛУБОКИЕ
  !  -------------
  !  *

       — Ты оказался прав,— говорю я Алеше,— но распечатал только одну строку.
       — Это потому, что числовой аргумент,— отвечает Алеша,— по умолчанию равен 1. Если я укажу его равным 5, по числу строк в нашем тексте

  +---------------
  !  *5L$$
  !  -
  !  ВОДЫ ГЛУБОКИЕ
  !  -------------
  !  ПЛАВНО ТЕКУТ
  !  ------------
  !  ЛЮДИ ПРЕМУДРЫЕ
  !  --------------
  !  ТИХО ЖИВУТ
  !  ----------
  !  А.ПУШКИН
  !  --------
  !  *

то увидим полный текст.
       — А что нужно сделать,— спрашиваю я,— для того, чтобы переместить слово "А.ПУШКИН" на несколько позиций вправо?
       — Нужно сначала переместить наш невидимый указатель на пятую строку, а затем вставить несколько пробелов,— отвечает Алеша.
       Так как мы уже стоим на первой строке, то нужно продвинуться на четыре строки. Английское слово Advance — продвинуться я сокращу до одной буквы и перед ним укажу числовой аргумент — 4. А для вставки нет лучшей команды, чем слово Insert — вставлять,— и его я также сокращу до одной буквы. Кроме того, я больше не буду подчеркивать тот текст, который печатает система или редактор, так как это будет понятно из контекста. И вот что у меня получилось:

  +---------------
  !  *4A$I    $L$$
  !  А.ПУШКИН
  !  *
  !

       — Ничего не понял,— Алеша задумался,— вставлял, вставлял, а увидел только последнее слово. Для того чтобы посмотреть предыдущие строки, укажу-ка я отрицательный аргумент:

  +---------------
  !  *-4L$$
  !  ВОДЫ ГЛУБОКИЕ
  !  ПЛАВНО ТЕКУТ
  !  ЛЮДИ ПРЕМУДРЫЕ
  !  ТИХО ЖИВУТ
  !
  !  *
  !

       — Опять непонятно,— сказал Алеша.
       — Ты забыл об указателе позиции в тексте,— объясняю я Алеше,— сначала ты передвинул его на четыре строки вниз. Потом вставил четыре пробела и этим так же сдвинул указатель, но уже на четыре позиции по строке. А так как команда List с положительным аргументом печатает текст от указателя и дальше, то ты увидел только слово "А.ПУШКИН".
       Когда ты распечатал текст с отрицательным аргументом, то команда List распечатала текст до указателя. Но так как после этого нужно было напечатать звездочку в начале следующей строки, то вместо пробелов (невидимых) ты увидел только пустую строку.
       Всю строку, на которой находится указатель, можно посмотреть следующим образом.

  +---------------
  !  *0LL$$
  !      А.ПУШКИН
  !  *
  !

       Команда 0L показывает текст от начала строки до указателя, а команда L показывает текст от указатели до конца строки. Для удобства эта последовательность команд может быть выполнена с помощью комбинированной команды Verify, которая показывает всю строку, на которой находится указатель.
       Но у Алеши оказался сложный случай, когда указатель текущей позиции находится между пробелами и текстом. И так как пробелы на экране не отображаются, то узнать, сколько их находится перед текстом, можно косвенным образом. Для этого нужно сначала распечатать всю строку, а затем ее часть после указателя.

  +---------------
  !  *VL$$
  !      А.ПУШКИН
  !  А.ПУШКИН
  !  *
  !

       И, чтобы закончить разговор о команде List, скажем, что команда /L распечатывает весь текст от указателя до конца буфера.
       — А мне кажется,— говорит Алеша,— что нужно еще вставить несколько пробелов. Для того чтобы было удобней считать, я сделаю это следующим образом.

  +---------------
  !  *-5LV$$
  !  ВОДЫ ГЛУБОКИЕ
  !  ПЛАВНО ТЕКУТ
  !  ЛЮДИ ПРЕМУДРЫЕ
  !  ТИХО ЖИВУТ
  !      А.ПУШКИН
  !  *I   $-5LV$$
  !  ВОДЫ ГЛУБОКИЕ
  !  ПЛАВНО ТЕКУТ
  !  ЛЮДИ ПРЕМУДРЫЕ
  !  ТИХО ЖИВУТ
  !         А.ПУШКИН
  !  *EX$$
  !  .
  !

       Т.е. распечатав несколько строк перед той, на которой стоит указатель,— объясняет свои действия Алеша,— и текущую строку на экране (или на бумаге), можно получить более полное представление о текущем состоянии текста. Кроме того, после завершения редактирования я могу распечатать этот текст на бумаге.
       — А для нас,— прошу я,— сделай еще и такой же дамп с расставленными кодами, как в предыдущем случае. Это позволит нагляднее увидеть результаты нашей работы.

  -------+-------------
         !ВОДЫ ГЛУБОКИЕ
         !ПЛАВНО ТЕКУТ
         !ЛЮДИ ПРЕМУДРЫЕ
         !ТИХО ЖИВУТ
         !       А.ПУШКИН

  167 157 144 171 040 147 154 165 142 157 153 151 145 015
   В   О   Д   Ы       Г   Л   У   Б   О   К   И   Е  012
   +---------------------------------------------------+
   V
  160 154 141 167 156 157 040 164 145 153 165 164 015
   П   Л   А   В   Н   О       Т   Е   К   У   Т  012
   +-----------------------------------------------+
   V
  154 140 144 151 040 160 162 145 155 165 144 162 171 145 015
   Л   Ю   Д   И       П   Р   Е   М   У   Д   Р   Ы   Е  012
   +-------------------------------------------------------+
   V
  164 151 150 157 040 166 151 167 165 164 015
   Т   И   Х   О       Ж   И   В   У   Т  012
   +---------------------------------------+
   V
  040 040 040 040 040 040 040 141 056 160 165 173 153 151 156 015
                               А   .   П   У   Ш   К   И   Н  012
  <------------------------------------------------------------+

       Вот теперь в дампе хорошо видно, что мы вставили семь пробелов перед словом "А.ПУШКИН".
       — Но, если ты заметил,— обращаю я внимание Алеши,— текст у нас оказался прижатым к краю бумаги, а правая часть совсем пустая. Если ты читал сборники стихов, то замечал, что стихи печатаются по середине страницы, или в крайнем случае отступив от начала обычного текста.
       — Я тоже могу отступить,— возразил Алеша,— только я вставлю в начало каждой строки символ горизонтальной табуляции (мы нажатие этой клавиши в редакторе будем обозначать — <ГТ>). Те пробелы, которые мы только что вставили, я заменю на два символа горизонтальной табуляции. Для этого потребуется выполнить следующие команды.

  +---------------
  !  .EDIT DX1:VERSE.TXT<ВК>
  !  *R5L$$
  !  ВОДЫ ГЛУБОКИЕ
  !  ПЛАВНО ТЕКУТ
  !  ЛЮДИ ПРЕМУДРЫЕ
  !  ТИХО ЖИВУТ
  !         А.ПУШКИН
  !  *I<ГТ>$AI<ГТ>$AI<ГТ>$AI<ГТ>$-3L2L$$
  !          ВОДЫ ГЛУБОКИЕ
  !          ПЛАВНО ТЕКУТ
  !          ЛЮДИ ПРЕМУДРЫЕ
  !          ТИХО ЖИВУТ
  !         А.ПУШКИН
  !  *

!

       Т.е я сначала прочитал первую страницу в буфер,— поясняет Алеша,— и распечатал наш текст на экране. При этом положение указателя текущей позиции в тексте не изменилось и он находился в первой позиции первой строки. Затем я вставил символ "ГТ" в начало первой строки и передвинул указатель на следующую строку, и так как команда Advance устанавливает указатель в начало строки, то я мог сразу вставлять символ "ГТ" и так далее.
       И наконец, последней группой команд я распечатал то, что у меня получилось. Команда -3L распечатала измененный текст, предшествующий указателю, а команда 2L распечатала то, что у меня осталось.
       Но, я не знаю, как мне удалить семь пробелов в начале следующей строки,— закончил свои объяснения вопросом Алеша.
       — Здесь есть несколько вариантов,— отвечаю я,— давай разберем их по очереди, от простого к сложному.
       Во-первых, можно как обычно продвинуться в начало следующей строки командой Advance и удалить семь символов командой 7Delete. При этом числовой аргумент действует так, как мы об этом говорили выше, т.е. положительный аргумент распространяет действие команды от указателя в сторону конца текста. А затем вставить два символа "ГТ". Таким образом, продолжая твои действия, это могло выглядеть так.

  +---------------
  !  *A$7D$I<ГТ><ГТ>$V$$
  !                  А.ПУШКИН
  !  *
  !

Во-вторых, следует отметить, что подобные операции удаления с последующей вставкой символов очень часто встречаются при редактировании текстов. Было бы разумно заменить эту комбинацию одной командой Change — замена. При этом числовой агрумент взят от команды Delete, а текстовой аргумент от команды Insert. Вот как это выглядит на практике.

  +---------------
  !  *A$7C<ГТ><ГТ>$V$$
  !                  А.ПУШКИН
  !  *
  !

       Эти два варианта демонстрировали действие символьноориентированных команд Delete и Change. Однако то же самое можно сделать и с помощью строкоориентированных команд. Иногда это бывает более удобным. Поэтому:
       В-третьих, можно полностью убить (Kill) следующую строку и вместо нее набрать новую. Команда Kill имеет числовой аргумент, который показывает сколько строк нужно удалить. А вставлять нужный текст мы будем любимой командой Insert. Вот как это делается.

  +---------------
  !  *A$K$I<ГТ><ГТ>А.ПУШКИН$V$$
  !                  А.ПУШКИН
  !  *

!

       В-четвертых, так же как мы комбинировали вместе команды Delete и Insert, можно скомбинировать команды Kill и Insert, получив при этом команду Exchange — обмен,— которая производит обмен указанного числовым аргументом количества строк текстового буфера и текстовым аргументом команды. Покажем это на примере.

  +---------------
  !  *A$1E<ГТ><ГТ>А.ПУШКИН$V$$
  !                  А.ПУШКИН
  !  *
  !

       И так же, как в предыдущем случае,— прошу я Алешу,— распечатай получившийся текст и дамп с расставленными кодами.

  -------+----------------
         !        ВОДЫ ГЛУБОКИЕ
         !        ПЛАВНО ТЕКУТ
         !        ЛЮДИ ПРЕМУДРЫЕ
         !        ТИХО ЖИВУТ
         !                А.ПУШКИН
 
  011 167 157 144 171 040 147 154 165 142 157 153 151 145 015
   .   В   О   Д   Ы       Г   Л   У   Б   О   К   И   Е  012
   +-------------------------------------------------------+
   V
  011 160 154 141 167 156 157 040 164 145 153 165 164 015
   .   П   Л   А   В   Н   О       Т   Е   К   У   Т  012
   +---------------------------------------------------+
   V
  011 154 140 144 151 040 160 162 145 155 165 144 162 171 145 015
   .   Л   Ю   Д   И       П   Р   Е   М   У   Д   Р   Ы   Е  012
   +-----------------------------------------------------------+
   V
  011 164 151 150 157 040 166 151 167 165 164 015
   .   Т   И   Х   О       Ж   И   В   У   Т  012
   +-------------------------------------------+
   V
  011 011 141 056 160 165 173 153 151 156 015
   .   .   А   .   П   У   Ш   К   И   Н  012
  <----------------------------------------+

       — Итак, Алеша,— говорю я,— твое стихотворение уже начало приобретать красивую форму. Но если уж редактировать его до конца, то давай сделаем все строки одинаковой длины и, чтобы у нас текст принимали в редакциях, расставим строчки через одну.
       — Я понимаю, что это не так сложно,— говорит Алеша,— но для этого нам нужно научиться двигаться по символам, иначе мы не сможем добраться до середины строки, т.е. до того места, где нам нужно вставлять пробелы.
       — И команда эта назывется Jump — прыжок,— подсказываю я,— а числовой аргумент используется как обычно с символьноориентированными командами.
       — Тогда,— берется за дело Алеша,— чтобы не считать пробелы в уме, я буду перед редактированием каждой строки распечатывать наш текст полностью (благо он небольшой) и вслед за ним текущую строку. Вот таким образом.

  +---------------
  !  .EDIT DX1:VERSE.TXT<ВК>
  !  *R10LV$$
  !          ВОДЫ ГЛУБОКИЕ
  !          ПЛАВНО ТЕКУТ
  !          ЛЮДИ ПРЕМУДРЫЕ
  !          ТИХО ЖИВУТ
  !                  А.ПУШКИН
  !          ВОДЫ ГЛУБОКИЕ
  !  *5J0L$$
  !          ВОДЫ
  !  *I $V$$
  !          ВОДЫ  ГЛУБОКИЕ
  !  *
  !

       Я не буду теперь разделять команды символами $,— поясняет Алеша,— там, где это допустимо. Кроме того, позицию указателя я буду проверять командой 0L, а результаты своих действий — командой V. И чтобы сгруппировать действия по функциям, я сначала расставлю пробелы, а потом займусь строками.

  +---------------
  !  *A7J-2L5LV0L$$
  !          ВОДЫ  ГЛУБОКИЕ
  !          ПЛАВНО ТЕКУТ
  !          ЛЮДИ ПРЕМУДРЫЕ
  !          ТИХО ЖИВУТ
  !                  А.ПУШКИН
  !          ПЛАВНО ТЕКУТ
  !          ПЛАВНО
  !  *I  $V$$
  !          ПЛАВНО   ТЕКУТ
  !  *
  !

       Эту сложную команду,— предлагает Алеша,— которую я только что выполнил, пусть читатели разберут сами, тем более что результаты ее работы хорошо видны в распечатке. А я продолжу дальше.

  +---------------
  !  *2A5J-5L5LV0L$$
  !          ВОДЫ  ГЛУБОКИЕ
  !          ПЛАВНО   ТЕКУТ
  !          ЛЮДИ ПРЕМУДРЫЕ
  !          ТИХО ЖИВУТ
  !          ТИХО ЖИВУТ
  !          ТИХО
  !  *4<I $>$V$$
  !          ТИХО     ЖИВУТ
  !  *
  !

       Теперь мне нужно вернуться в начало буфера,— говорит Алеша,— не нужно долго думать, чтобы понять, что команда для этого будет называться Beginning. И разбивку по строкам можно выполнить одной сложной командой.

  +---------------
  !  *B$4<AI<ВК><ПС>$A>A$-10LV$$
  !          ВОДЫ  ГЛУБОКИЕ
  !
  !          ПЛАВНО   ТЕКУТ
  !
  !          ЛЮДИ ПРЕМУДРЫЕ
  !
  !          ТИХО     ЖИВУТ
  !
  !                  А.ПУШКИН
  !  *EX$$
  !  .
  !

       Завершив редактирование,— говорит Алеша,— я распечатаю то, что у нас получилось, и дамп с расставленными кодами.

  -------+--------------
         !        ВОДЫ  ГЛУБОКИЕ
         !
         !        ПЛАВНО   ТЕКУТ
         !
         !        ЛЮДИ ПРЕМУДРЫЕ
         !
         !        ТИХО     ЖИВУТ
         !
         !                А.ПУШКИН
 
  011 167 157 144 171 040 040 147 154 165 142 157 153 151 145 015
   .   В   О   Д   Ы           Г   Л   У   Б   О   К   И   Е  012
  015 012 <----------------------------------------------------+
  """/"""
  011 160 154 141 167 156 157 040 040 040 164 145 153 165 164 015
   .   П   Л   А   В   Н   О               Т   Е   К   У   Т  012
  015 012 <----------------------------------------------------+
  """/"""
  011 154 140 144 151 040 160 162 145 155 165 144 162 171 145 015
   .   Л   Ю   Д   И       П   Р   Е   М   У   Д   Р   Ы   Е  012
  015 012 <----------------------------------------------------+
  """/"""
  011 164 151 150 157 040 040 040 040 040 166 151 167 165 164 015
   .   Т   И   Х   О                       Ж   И   В   У   Т  012
  015 012 <----------------------------------------------------+
  """/"""
  011 011 141 056 160 165 173 153 151 156 015
   .   .   А   .   П   У   Ш   К   И   Н  012
  <----------------------------------------+

 

9.4. Контекстный поиск

       — Тот набор команд,— говорю я Алеше,— который мы использовали при редактировании стихотворения, является достаточным для создания и редактирования практически любого текста.
       — Он даже является избыточным,— замечает Алеша,— ведь в нем есть комбинированные команды.
       — И в то же время,— продолжаю я,— для эффективной работы желательно иметь набор команд, позволяющий найти в тексте заданную последовательность символов. Т.е. то, что называется контекстным поиском.
       Основная команда для поиска Get — получить — ищет в текстовом буфере текущей страницы последовательность символов, которая задана в ее текстовом аргументе. А что, по-твоему,— спрашиваю я Алешу,— будет обозначать числовой аргумент?
       — Так как команда Get,— ищет ответ Алеша,— не работает ни со строками, ни с символами, то, скорее всего, числовой аргумент будет обозначать число повторений поиска. Т.е. если заданная последовательность символов встречается в тексте несколько раз, то ее N-ое появление можно найти, задав N в качестве числового аргумента в команде Get.
       — Молодец, Алеша,— говорю я,— только нужно отметить, что в силу того, что ты сейчас сказал, числовой аргумент не может быть отрицательным или равным нулю, а только положительным.
       Еще одно свойство команды Get заключается в ограниченности ее действия. Поиск осуществляется только в пределах текстового буфера страницы. Более сильная команда Find — искать — ищет по всему файлу, и по своей сути является комбинированной командой Get, Next. Однако так как мы не можем прочитать из выходного файла уже записанную страницу, то такой поиск может осуществляться только в одну сторону — от начала файла к его концу. Для возвращения в начало файла нужно закрыть выходной файл командой EXit, завершив при этом сеанс редактирования, и начать новый сеанс.
       — Команда Get,— добавляет Алеша,— тоже не умеет искать назад, но я могу дать команду Beginning и вернуться в начало буфера.
       — И еще нужно отметить общее свойство команд поиска в EDIT,— продолжаю я,— указатель текущей позиции после завершения поиска устанавливается в конец найденной модели поиска.
       — И других вариантов поиска,— спрашивает Алеша,— вроде бы не существует?
       — Ошибаешься,— поправляю я его,— ты мог бы заметить, что команда Find переписывает в выходной файл все страницы, поиск в которых оказался неуспешным. В то же время, чтобы уравновесить команду End File, которая позволяет в таком случае создать выходной файл из первой части входного файла, была введена команда Position, которая позволяет быстро получить выходной файл из второй части входного. Для этого необходимо в тексте иметь некоторую последовательность символов, которая является разделителем частей файла. Затем осуществляются следующие действия.

  +---------------
  !  .EDIT BIGFILE.TXT<ВК>
  !  *R$$                  - чтение первой страницы
  !  *PКОНЕЦ 1 ЧАСТИ$$     - поиск разделителя
  !  *EX$$                 - запись оставшейся части в файл
  !  .
  !

       — А если мне нужно установить указатель в начало найденной модели поиска,— спрашивает Алеша,— я должен сам считать, на сколько символов мне нужно вернуться?
       — Ты правильно заметил эту особенность,— отвечаю я ему,— поэтому мы, несмотря на некоторые повторения, суммируем все свойства числового аргумента:

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

-N
       — указывает число символов или строк, которое используется в операции, и предшествует указателю текущего положения;

0
       — указывает на текст от начала текущей строки до указателя текущего положения;

/
       — указывает на текст от указателя текущего положения и до конца текстового буфера;

=
       — определяет количество символов, которое было использовано в предыдущем текстовом аргументе.

       Последнее можно пояснить на примере. Если мы искали некоторое слово и хотим вернуться в начало найденной модели поиска, то должны дать следующую последовательность команд:

      GПРЕМУДРЫЕ$=J$$

       Таким образом, комбинация "=J" вернет указатель текущего положения назад на длину предыдущего текстового аргумента.
       — И также, наверное, можно удалять символы,— говорит Алеша,— если мы хотим удалить всех премудрых из файла, то должны дать такую последовательность команд:

100<FПРЕМУДРЫЕ$=D$>$$

       — Это ты написал правильно,— говорю я,— но можно не удалять премудрых, а заменить их, например, на умных. Для этого можно дать такую последовательность команд:

      100<FПРЕМУДРЫЕ$=CУМНЫЕ$>$$

       Других случаев применения знака "=" нет, потому что он работает только с символами.

 

9.5. Другие полезные команды

       — А что, разве при редактировании текста может еще что-нибудь понадобиться?— удивленно спрашивает Алеша.
       — Конечно,— отвечаю я,— дополнительный сервис всегда полезен, если он удобно выполнен.
       Например, очень часто нужно переставить в тексте значительные куски текста или вставить один и тот же текст в разных частях файла. Для этого нужно уметь сохранять текст в каком-то особом буфере и иметь команды восстановления текста из него.
       EDIT выделяет память для такого буфера динамически, т.е. в зависимости от размера доступной памяти в системе, от размера текстового буфера и др. Каких-либо особых действий со стороны пользователя для этого не требуется. Достаточно дать команду Save — сохранить,— числовой аргумент которой определяет число строк, которое необходимо сохранить в буфере, от указателя текущего положения в сторону конца текстового буфера. Т.е. числовой аргумент может быть только положительным. Команда Save не изменяет содержимое текстового буфера и положение указателя текущей позиции в нем.
       — Тогда я знаю команду,— говорит Алеша,— которая восстанавливает текст из буфера — это Unsave. Естественно, что она не изменяет содержимое Save-буфера и не требует никаких аргументов.
       — Может быть,— спрашиваю я,— ты сможешь назвать команду, которая очищает этот буфер сохранения?
       — Я попробую ее вычислить,— отвечает Алеша,— мы не можем для этого использовать команду 0S, так как по логике предыдущих команд это означало бы сохранение текущей строки от начала до указателя текущего положения. С другой стороны, команда 0U не имела бы смысла в контексте восстановления, так как мы не можем восстанавливать буфер 0 раз. Если рассматривать комбинацию 0U как особый случай, то можно принять его за команду очистки буфера сохранения.
       — Превосходно, Алеша,— хвалю я его за грамотный анализ языка,— тогда мы можем познакомиться еще с одним буфером.
       По аналогии с текстовым буфером сохранения, можно говорить и о буфере сохранения команд.
       По определению Краткого Оксфордского словаря английского языка префикс macro происходит от греческого macros, обозначающего "длинный" или "большой". Как префикс macro употребляется во многих составных научных словах, таких, как "макрокосмос" (обозначающем Вселенную) и "макроскопический" (обозначающем видимый невооруженному глазу). В программировании термин макрос используется в том же смысле, поскольку по одной макрокоманде обычно генерируется длинная последовательность основных команд. Таким же образом можно запомнить последовательность команд в редакторе текста и затем использовать ее много раз, как одну большую команду.
       — А зачем макрокоманда нужна в редакторе текста?— не понял Алеша.
       — Простейшие случаи применения макрокоманды,— отвечаю я,— встречаются очень часто. Например, нужно во всем тексте заменить несколько подряд идущих пробелов на один или убрать пробелы, стоящие перед точкой. И EDIT поддерживает такую возможность отдельной командой.
       — А название у нее будет Macro,— говорит Алеша,— и у нее не будет числового аргумента.
       — Все это так,— продолжаю я,— но нас ждет проблема, как отделить одни команды от других, например от самой команды Macro. Для этого используются специальные символы — ограничители. Они выбираются пользователем и должны отвечать следующим условиям: быть парными, т.е один начинает макрокоманду, второй — завершает, и не встречаться в тексте макрокоманды. Например:

       M/GПРЕМУДРЫЕ$=CУМНЫЕ$/$$

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

     M/GПРЕМУДРЫЕ$=CУМНЫЕ$GПРЕМУДРЫЕ$=J-JV$/$$

       Это позволит перед повторным выполнением макрокоманды подумать, — а нужно ли ее выполнять в данном месте.
       — А я опять могу назвать команду для выполнения этой макрокоманды,— вставляет Алеша,— "выполнить" по-английски будет EXECUTE, поэтому команда будет называться Execute Macro, и сократить ее нужно до двух букв — EM. После определения макрокоманды ее можно выполнить в любом месте следующим образом:

  +---------------
  !  *EM$$
  !

       Она также может иметь числовой аргумент, который указывает, сколько раз ее нужно выполнить. Макрокоманду можно заключать в угловые скобки и включать в цепочки обычных команд. Уфф!!
       — Ну и ну,— подыгрываю я уставшему Алеше,— тогда уж скажи, как очистить буфер макрокоманд.
       — Это совсем просто,— перевел дух Алеша,— во-первых, буфер макрокоманд обновляется при определении новой макрокоманды. Во-вторых, это следует из предыдущего если мы дадим определение макрокоманды с пустым аргументом, то буфер, естественно, очистится. Например, так:

      M//$$

       И, в-третьих, по аналогии с очисткой текстового буфера сохранения, можно дать определение макрокоманды с нулевым числовым аргументом.
       — Наконец,— завершаю я разговор о полезных командах,— есть команды, включенные в EDIT просто для удобства работы.
       Например, если ты помнишь, что мы говорили о верхнем и нижнем регистрах кода ASCII, то EDIT позволяет управлять этими регистрами. По-английски верхний регистр называется Uppercase и определяет прописные буквы, а нижний регистр называется Lowercase, который определяет строчные буквы. EDIT позволяет при вводе символов нижнего регистра автоматически переводить их в символы верхнего регистра. Для этого нужно использовать команду Edit Upper (EU). Для разрешения ввода символов обоих регистров используется команда Edit Lower (EL). При этом следует отметить, что символы, вводимые как команды, всегда переводятся в верхний регистр.
       И последняя команда просто позволяет посмотреть номер версии редактора EDIT. Она так и называется Edit Version (EV).

9.6. Сообщения об ошибках

       Такие достаточно большие интерактивные программы, как текстовой редактор, как правило, должны иметь богатый набор сообщений об ошибках, в противном случае пользователь очень часто будет попадать в тупиковые ситуации. Ниже приводятся сообщения текстового редактора EDIT, поставляемого с RT-11 V5.4.

"<>" error
       — Ошибка скобок
       При группировке команд с помощью угловых скобок была нарушена парность левых и правых скобок.

Invalid argument
       — Неверный аргумент
       При вводе команды был указан неверный, как правило числовой, аргумент. Проверьте командную строку.

Invalid command
       — Неверная команда
       Как правило, сообщение выдается, когда пропущена команда Insert, и первый символ текстового аргумента воспринимается как имя команды, которой не существует.

?EDIT-W-Command bufer almost full
       — Буфер команд почти заполнен
       Первый раз сообщение выдается, когда в буфере команд осталось 10 свободных символов. Необходимо завершить команду в пределах этих 10 символов. Сообщение будет выдаваться при вводе каждого символа в этой критической зоне.

Command buffer full; no command(s) executed
       — Буфер команд полон, команды не выполнялись
       Вы не смогли уложиться в 10 символов критической зоны, поэтому команду(ы) нужно набирать заново.

Insufficient memory
       — Недостаточно памяти
       Сообщение выдается, когда не хватает памяти для одного из буферов — текстового буфера текущей страницы, буфера сохранения текста или буфера макрокоманд. Так как размеры буферов определяются динамически, то уменьшение размера любого буфера освобождает место для других. Уменьшение текстового буфера текущей страницы достигается переписыванием его части в выходной файл. Для уменьшения буфера сохранения текста нужно уменьшить количество строк запоминаемого текста.

Search failed
       — Неудачный поиск
       Как правило, при многократном поиске или поиске в составе макрокоманды был обнаружен конец файла или, если использовалась команда Get, конец текстового буфера. В большинстве случаев на эту ошибку можно не реагировать.

Invalid macro
       — Неверная макрокоманда
       При определении макрокоманды допущена ошибка. Необходимо проверить определение макрокоманды и в первую очередь символы-ограничители.

End of input file
       — Конец входного файла
       При выполнении какой-либо команды, например Read, Next, достигается конец входного файла.

Input error
       — Ошибка чтения входного файла
       При выполнении команд Read, Next, Find, Position произошла ошибка чтения входного файла.

Output file full
       — Выходной файл полон
       При редактировании в файл вставлено текста больше, чем это возможно при текущем размере открытого выходного файла.

Invalid device — Неверное устройство
       При попытке открыть файл в спецификации было указано неверное устройство. Иногда может оказаться, что не загружен драйвер этого устройства.

File not found
       — Файл не найден
       При попытке открыть файл имя файла, указанное в спецификации, не найдено в каталоге указанного устройства.

No file open for output
       — Не открыт файл для вывода
       Попытка выполнить команды Write, Next и им подобные, не открывая файла для вывода.

Directory full
       — Каталог полон
       При попытке открыть выходной файл оказывается, что нет места в каталоге для записи о файле (см. 5 главу).

Invalid file name
       — Неверное имя файла
       При открытии файла была допущена ошибка в имени файла — либо неверный символ, либо слишком длинное, более 6 символов, имя.

System I/O error
       — Ошибка системного ввода/вывода.

Device full
       — Устройство заполнено
       На устройстве, предназначенном для выходного файла, нет достаточно места.

No file open for input
       — Не открыт входной файл
       Попытка прочитать следующую текстовую страницу из входного файла, когда он не был открыт. Например, при создании нового текста, когда открыт только выходной файл.

Output error
       — Ошибка вывода
       При выполнении команд Write, Next и им подобных произошла ошибка устройства или носителя. Рекомендуется прервать сеанс редактирования и проверить устройство на плохие блоки.

Command aborted
       — Выполнение команды прервано
       При выполнении команды встретилась ошибка, препятствующая дальнейшему выполнению команды. Рекомендуется не строить очень длинные последовательности команд.

Protected file already exists
       — Защищенный файл уже существует
       При попытке открыть выходной файл на этом же устройстве обнаружен файл с таким же именем и типом.

?EDIT-W-Superseding existing file
       — Существующий файл заменен
       EDIT печатает это предупреждающее сообщение в ответ на команды EXit, End File, Edit Write, если на выходном устройстве уже был файл с указанным именем и типом.

       — И несколько слов в заключение,— обращаюсь я к Алеше и к нашим читателям,— на протяжении всей книги мы занимались проблемами, которые практически невозможно запомнить — их нужно понять и прочувствовать. Это в особенной мере касается редактора текстов EDIT. И не только потому, что указатель текущей позиции никак не отображается. Его нужно чувствовать, он должен постоянно отображаться в нашем сознании. Это понимание в дальнейшем сильно облегчит работу с мощными экранными текстовыми редакторами.
       Здесь рекомендуется прервать чтение книги и поработать некоторое время с редактором EDIT, написать какие-нибудь тексты, например письма к родным, а заодно проверить понимание предыдущего материала.

(c) 1992г Архангельский Андрей Германович




Поддержите культуру
ЯндексЯндекс. ДеньгиХочу такую же кнопку

Google
 
Web azdesign.ru az-libr.ru


Дата последнего изменения:
Wednesday, 06-Nov-2013 08:33:58 UTC