Рабочая папка и 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. Если этого не сделать, кириллические символы будут переданы неправильно.
Собственно, все.