вторник, 13 января 2009 г.

popen++

Дабы не терять практики в C++ решил опубликовать одну свою старую библиотеку: popen++, которая позволяет создавать дочерние процессы и работать с их потоками (ввода, вывода и ошибок), как со стандартными потоками C++. Например так:
process::popen child = process::popen2("python");

child.stdin() << "print 'TEST_STRING'" << std::flush;
child.close_stdin();

std::string test_string;
child.stdout() >> test_string;
Работает как в Linux (по-хорошему, в POSIX, кажестя один раз проверял для FreeBSD, но уже не помню), так и в Windows (собственно, из-за неё и стал делать эту библиотеку, для Linux в тот момент вполне устраивала PStreams)

Сделано в основном под влиянием соответствующих средств стандартной библиотеки Python. Кроме того, создаваемый объект popen можно использовать в качестве фильтра для boost.iostreams. Также, очень полезной для меня оказалась функция:
void transfer(popen& proc, std::istream& in, std::ostream& out);
Которая позволяет прогнать данные из одного потока в другой через дочерний процесс. Тонкость в том, что некоторые программы (например, Ghostscript) начинают вывод ещё до того, как будет полностью закончен ввод и наивная попытка сначала закачать в такую программу все данные, и только потом попытаться получить вывод может (в случае большого объёма данных) нарваться на ограничение размеров системного буфера и привести к зависанию программы. Правда, в данный момент это корретно реализовано только для Linux (потребности в данной фунции в Windows у меня не возникало, хотя там есть теже проблемы).

Библиотека зависит от boost, какая минимальная версия подходит точно не скажу, но поскольку активно используются возможности boost.iostreams, то точно не ниже 1.33.0.

Для сборки сейчас используется SCons. Написать нормальный "конфигуратор" мне лень, поэтому при желании изменить опции (совершенно необходимо для Windows, где требуется указать путь к boost) необходимо править SConstruct. Я собираю так:
cd popen++
scons
./test+popen++
scons install

четверг, 25 декабря 2008 г.

sbcl-slime, clisp-slime and etc

Хотелось бы поделиться двумя советами, которые представляются мне довольно важными при использовании Slime (а если вы работаете с Common Lisp, то почти наверняка используете именно его).

Как известно, какая именно реализация CL будет запущена при запуске Slime определяется переменной inferior-lisp-program. Однако глобальное определение этой переменной и использование команды slime довольно неудобно, поскольку не позволяет легко запускать различные реализации CL. Я же часто запускаю как sbcl, так и clisp, а в планах поработать и с другими реализациями. Не переопределять же эту переменную каждый раз, когда хочешь поработать с другой реализацией? Поэтому, в свой конфиг Emacs я добавил следующее:
(defmacro lisp-slime (lisp path &optional coding)
(let ((funname (intern (format "%s-slime" lisp))))
`(defun ,funname ()
(interactive)
(let ((inferior-lisp-program ,path)
(slime-net-coding-system (or ,coding 'utf-8-unix)))
(slime)))))

(lisp-slime sbcl "/usr/bin/sbcl")
(lisp-slime clisp "/usr/bin/clisp")
Теперь у меня доступны команды sbcl-slime и clisp-slime, которые позволяют легко запустить sbcl или clisp соответственно. Ну а макрос lisp-slime может быть использован для лёгкого добавления других реализаций.

Второй совет связан с использование hyperspec. Функция hyperspec-lookup отрывает документацию по символу в браузере и очень удобно, если это emacs-w3m. Для того, что бы так и происходило (в моей системе по умолчанию запускается Firefox), можно просто переопределить функцию browse-url-default-browser таким образом, что бы она вызывала w3m-browser-url. Однако, в таком случае функция browser-url всегда будет открывать указанный url в emacs-w3m, чего бы мне хотелось избежать (w3m хорош для работы с hyperspec, но для других задач я предпочитаю использовать Firefox). Добиться того, что бы hyperspec открывался в emacs-w3m (в том числе, при использовании slime-hyperspec-lookup), а другие url в браузере по умолчанию (в моём случае в Firefox) можно следующим образом:
(require 'hyperspec)

(defun hyperspec-lookup (&optional symbol-name)
(interactive)
(let ((browse-url-browser-function 'w3m-browse-url))
(if symbol-name
(common-lisp-hyperspec symbol-name)
(call-interactively 'common-lisp-hyperspec))))
Примечание: хотя в моей системе hyperspec загружается автоматически, мне всё же пришлось добавить (require 'hyperspec) до определения hyperspec-lookup, что бы гаранитровать правильный порядок инициализации.

среда, 24 декабря 2008 г.

Переход на git

Начал эксперимент, по переводу одного из внутренних проектов на git, если всё пройдёт успешно (а думаю, что так оно и будет), то буду переводить все свои проекты с subversion на git.

вторник, 23 декабря 2008 г.

garbage-pools-0.1.1

Добавил в garbage-pools одну функцию: cancel-object-cleanup, которая позволяет отменить регистрацию ранее зарегистрированного в пуле объетка. Это приём в стиле C++ : вообще-то, удалять ресурс не собираемся, но в случае возникновения исключения он должен быть удалён, поэтому готовим его к удалению, а в после успешного прохождения опасной зоны спасаем и используем по назначению.

Поскольку успел заюзать эту функцию в cl-libxml2, то в связи с её новым релизом, пришлось строчо выпустить garbage-pools версии 0.1.1 (чуть не забыл это сделать).

cl-libxml2-0.2.5

Выпустил cl-libxml2 версии 0.2.5. В этой версии:
  1. Появилась обработка ошибок: теперь все ошибки, генерируемые libxml2, транслируются в conditions или warnings (для нефатальных ошибок).
  2. Кроме того, понаводил порядка в исходниках, что вылилось в достаточно заметное изменение их структуры.
  3. В результате выполнения предыдущих двух пунктов вылезло на свет некоторое колличество багов, которые и были исправлены.
Как личное достижение могу отметить то, что на данный момент ознакомился с исходным кодом libxml2 процентов на 30% - документации по библиотеке, я бы сказал, не вполне вменяема, пока код не посмотришь - ничего толком не поймёшь. Так же обнаружил, что в некоторых местах html-документация "не совсем" соответствует комментариям в исходниках, что немного насторожило...

А тем временем, в gentoo-lisp-overlay появилась Xuriella XSLT, а ещё немного ранее уже был добавлен Plexippus XPath. Появись это хотя бы на полгода раньше, то вероятно начинать cl-libxml2 я бы не стал. Однако, теперь забрасывать этот проект не при каких обстоятельствах не собираюсь: полноценная поддержка xml критически важна для меня, а упомянутые проекты ещё сыроваты (им ведь в самом деле приходится писать реализация, а я только обёртку делаю для давно и хорошо известной библиотекой).

четверг, 18 декабря 2008 г.

"Ни дня без строчки" или cl-routes-0.1.5

Выпустил cl-routes версии 0.1.5, в состав пакета включил hunchentoot-routes.asd, который позволяет производить маршрутизацию не только по структуре url, но также по хосту (очень люблю vhost в apache) и методу запроса, типа:
(routes.h:connect-handler *map*
"index.html"
'handler-for-post-query-on-index.html
:host "archimag:8080"
:method :post)
Конечно, routes.asdf всё это тоже поддерживает, но нужно понимать как он работает, что бы этим воспользоваться, а тут всё довольно прозрачно.

На мой взгляд, довольно неплохо для начала.

Тут, правда, возник другой насущный вопрос: где бы мне раздобыть ntlm-аутенфикацию для hunchentoot? Пропускать его (hunchentoot) через apache не хочу. Что, опять писать самому?

вторник, 16 декабря 2008 г.

wget and sed всех победят!

Я вот не понимаю, зачем люди выкладывают книги в веб в html и при этом не дают возможности скачать архив? Что бы отнять у заинтересовавшегося пять минут времени? Захотел вот книжку скачать, Practical PostgreSQL, а архива нет, по крайней мере, не нашёл.

Ну да впрочем, искал я недолго:
wget -m -np http://www.commandprompt.com/ppbook/
Отлично, открываю - а там все ссылки абсолютные, типа /ppbook/p206. Нет думаю, нас так просто не возьмёшь:
sed -i -e "s/\/ppbook\///" *[[:digit:]]**
(такая маска нужна, что бы каталог images пропустить, а так там всё с цифрами)

Докачал css-файлы и изменил ссылки на них.

Кроме того, мне не понравились , что верхние части страниц занимает всякий мусор с http://www.commandprompt.com/, там ссылки на Home, About, поиск какой-то, короче, мне совершенно не нужные вещи. Решил победить:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:html="http://www.w3.org/1999/xhtml"
version="1.0">

<xsl:output method="html" public="-//W3C//DTD XHTML 1.0 Transitional//EN" system="DTD/xhtml1-transitional.dtd">

<xsl:template match="/">
<xsl:copy>
<xsl:copy-of select="@*">
<xsl:apply-templates select="*">
</xsl:copy>
</xsl:template>

<xsl:template match="div[@id='widetop']">
<xsl:template match="ul[@id='greymenu_wide']">

<xsl:template match="*|text()">
<xsl:copy>
<xsl:copy-of select="@*">
<xsl:apply-templates select="*|text()">
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Это xslt-преобразование копирует входящий html документ, вырезая из него блоки <div id="widetop"> и <ul id="greymenu_wide">
Плюс потребовался небольшой скрипт:
for path in $@
do
name=`echo $path | sed -e 's/ppbook\///'`
`xsltproc --html --novalid ppbook.xsl ppbook/$name > ppbook-copy/$name`
echo $name
done
Который был вызван следующим образом:
 ./ppbook.sh ppbook/*[[:digit:]]** 
И всё отлично работает. Но полчаса времени я потерял. Вот и спрашивается, зачем людям жизнь осложнять?