Я пытаюсь создать собственный канал tcl и использовать его для получения выходных данных интерпретатора tcl. Я добавил реализацию нескольких функций Tcl_ChannelType, но получаю segfault.
#include <tcl.h>
#include <iostream>
int driverBlockModeProc(ClientData instanceData, int mode) {
std::cout << "driverBlockModeProc\n";
return 0;
}
int driverCloseProc(ClientData instanceData, Tcl_Interp *interp) {
std::cout << "driverCloseProc\n";
return 0;
}
int driverInputProc(ClientData instanceData, char* buf, int bufSize, int *errorCodePtr) {
std::cout << "driverInputProc\n";
return 0;
}
int driverOutputProc(ClientData instanceData, const char* buf, int toWrite, int *errorCodePtr) {
std::cout << "driverOutputProc\n";
return 0;
}
int main() {
Tcl_ChannelType *typePtr = new Tcl_ChannelType;
typePtr->blockModeProc = driverBlockModeProc;
typePtr->outputProc = driverOutputProc;
typePtr->closeProc = driverCloseProc;
typePtr->inputProc = driverInputProc;
typePtr->seekProc = NULL;
typePtr->setOptionProc = NULL;
typePtr->getOptionProc = NULL;
typePtr->watchProc = NULL;
typePtr->getHandleProc = NULL;
typePtr->close2Proc = NULL;
typePtr->blockModeProc = NULL;
typePtr->flushProc = NULL;
typePtr->handlerProc = NULL;
typePtr->wideSeekProc = NULL;
typePtr->threadActionProc = NULL;
ClientData data = new char[200];
Tcl_CreateChannel(typePtr, "im_chanel", data, TCL_WRITABLE | TCL_READABLE);
}
Я не могу отладить segfault, потому что его источник недоступен. Я думаю, что segfault потому, что вызывается функция, которая имеет значение NULL. Мне нужно только использовать канал, чтобы получить вывод интерпретатора. Какие функции мне не нужно реализовывать, и это верное направление для решения проблемы.
При работе на этом уровне рекомендуется загрузить исходный код в Tcl. Я не уверен, какую версию вы используете, но все официальные дистрибутивы исходного кода, идущие очень давно, включены система распространения файлов SourceForge; выберите точное соответствие для версии, которую вы получили.
Создание собственного драйвера канала не легко. Это связано со значительной сложностью, и не очень хорошо задокументировано, какие «методы» в типе драйвера канала являются обязательными, а какие — необязательными. (Они не являются методами C ++ в классе — Tcl — это чистый код на C по причинам, которые здесь слишком длинны, но они функционируют концептуально схожим образом.)
Если мы посмотрим на документацию для Tcl_CreateChannel
, мы видим (довольно далеко вниз по этой странице) определение структуры типа канала. Структура типа канала должна быть статически распределенный (Реализация Tcl предполагает, что он никогда не меняет местоположение), и следующие поля должны быть установлены на что-то значимое:
typeName
— Это название типа канала, полезное для отладки!version
— это версия типа канала; Вы должны установить его на последнюю версию, поддерживаемую вашим целевым уровнем источника. (Рекомендуется использовать хотя бы TCL_CHANNEL_VERSION_2
или все становится сложнее.) closeProc
или же close2Proc
— Каналы должен быть близким, но у вас есть два варианта способов сделать это. Двунаправленные каналы должен использовать close2Proc
, но не обязательно.inputProc
— нужен только если вы читаете; позаботьтесь, чтобы справиться с этим правильно.outputProc
— нужен только если пишешь; позаботьтесь, чтобы справиться с этим правильно.watchProc
— Вызывается, чтобы сообщить драйверу канала, что он должен установить себя в систему событий, чтобы получать подходящие события (в соответствии с инструкциями, предоставленными битовой маской). Каналы, у которых нет дескрипторов ОС, используют события таймера или просто никогда не генерируют события (в этом случае они никогда не станут доступными для чтения или записи с точки зрения fileevent
).Глядя на ваш код, я вижу, что вам не хватает watchProc
, Я знаю, что это трудно увидеть (не многие пишут драйверы каналов, если честно, поэтому документация не очень «проверена»), но это действительно необходимо.
Других решений пока нет …