Рабочая папка и qpile

Известная проблема: в процессе работы терминала QUIK изменяется рабочая папка. При этом программы, написанные на QPILE, перестают находить файлы, если их чтение/запись осуществляется не по полному пути, а только по имени и расширению.

Разработчики прекрасно осведомлены о имеющейся проблеме, и предоставили механизм для ее решения в реализации языка qlua. Ждать  изменений для Qpile, очевидно, смысла нет. Поэтому приходится решать проблему своими силами.

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

Сформулируем задачу. QPILE портфель должен писать и читать файл, который имеет то же самое имя, что и сам портфель, а расширение у него пусть будет .INI

Скажем, портфель лежит в файле Arb-Calend.qpl. А папка, в которой он лежит, имеет имя из смеси латиницы и кириллицы: E:\Google Диск\ROBOT\Arb. Нам будет нужно читать и писать в процессе работы портфеля файл, лежащий в том же самом каталоге с именем Arb-Calend.ini

Можно просто написать полный путь руками и при изменении местоположения файла (смены машины) каждый раз искать и изменять этот путь, попутно рискуя набить что-то не так.

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

Третий путь - использование препроцессора. Создаем макрос __directory__, который всегда будет разворачиваться в полный путь к файлу портфеля. При любом изменении местоположения qpl файла достаточно пройтись препроцессором по нему, чтобы получить копию, сразу настроенную на текущий путь. В принципе, это тот же инсталлятор, только написанный за пару минут.

Вот как это выглядит. Добавляем в начало текста qpile портфеля несколько макроопределений:

 

define(`m4_len',defn(`len'))
undefine(`len') define(`m4_substr',defn(`substr'))
undefine(`substr') define(`m4_trim_cr_lf',`m4_substr(`$1',0,eval(m4_len(`$1')-2))') define(`__directory__',`m4_trim_cr_lf(esyscmd(chcp 1251|echo %cd%))') PORTFOLIO_EX Arb-Calend;
DESCRIPTION Календарный арбитраж;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST FIRMID;
USE_CASE_SENSITIVE_CONSTANTS;
PROGRAM
.... начало текста портфеля ......
IniFile = "__directory__\Arb-Calend.ini" .......... весь остальной текст портфеля ...

После обработки препроцессором текст будет выглядеть так:

 

PORTFOLIO_EX Arb-Calend;
DESCRIPTION Календарный арбитраж;
CLIENTS_LIST ALL_CLIENTS;
FIRMS_LIST FIRMID;
USE_CASE_SENSITIVE_CONSTANTS;
PROGRAM
.... начало текста портфеля ......
IniFile = "E:\Google Диск\ROBOT\Arb\Arb-Calend.ini"  .......... весь остальной текст портфеля ...

Никаких лишних символов, а путь к файлу заменен на текущий.

Как это работает.

  • сначала идет переопределение стандарных макросов M4. Дело в том, что зарезервированные слова Len и Substr используются не только в qpile, но и являются стандартными макросами M4. Препроцессор позволяет переопределить любые свои макросы, чтобы не случались коллизии с основным языком. Чем мы и воспользовались.
  • Следующий макрос отрезает из строки 2 крайних правых символа. Это вспомогательный макрос. В нашем случае это необходимо, чтобы убрать символы CR и LF в конце строки, которые нам будет упорно возвращать командный интерпретатор.
  • Далее определяется макрос __directory__, ради которого все и затевалось. Его упоминание далее в любом месте текста будет заменено препроцессором на полный путь. При выполнении этого макроса будет запущен интерпретатор командной строки Windows и в нем будет исполнена команда echo %cd%, которая нам сообщит полный путь к текущей рабочей папке. Однако до этого будет переключена кодовая таблица. Дело в том, что стандартной для DOS является страница с кодом 866, а нам нужно получить текстовую строку в стандартной кодировке Windows 1251. Если этого не сделать, кириллические символы будут переданы неправильно.

Собственно, все.

Добавить комментарий


Защитный код
Обновить