Обработка команды выхода, выполняемой встроенной средой выполнения Tcl

У меня есть небольшое приложение оболочки, которое встраивает Tcl для выполнения некоторого набора Tcl код. Интерпретатор Tcl инициализируется с помощью Tcl_CreateInterp. Все очень просто:

  1. пользовательские типы команда Tcl
  2. команда передается в Tcl_Eval для оценки
  3. повторение

Но если пользователь набирает «exit», что является допустимой командой Tcl, все это - интерпретатор Tcl и мое приложение оболочки - завершается автоматически.

В: есть ли способ поймать этот сигнал выхода, исходящий от интерпретатора Tcl. Очень бы хотелось не проверять каждую пользовательскую команду. Я попробовал Tcl_CreateExitHandler, но это не сработало.

Большое спасибо.


person ilya1725    schedule 29.03.2012    source источник
comment
Исправлено название и удалены ссылки на tcllib, поскольку под этим именем широко известна стандартизированная библиотека для Tcl . На самом деле вы, кажется, имеете в виду встраивание среды выполнения Tcl в вашу программу.   -  person kostix    schedule 29.03.2012
comment
Tcl_CreateExitHandler предназначен для перехвата выходов и освобождения ресурсов (например, соединений с базой данных), которые в противном случае злобно зависают. Это не может остановить выход.   -  person Donal Fellows    schedule 29.03.2012
comment
На самом деле это именно то, что я хочу сделать - высвободить ресурсы при выходе. Почему в этом случае Tcl_CreateExitHandler не сработает?   -  person ilya1725    schedule 29.03.2012


Ответы (3)


Избавьтесь от команды

rename exit ""

Или переопределите его, чтобы пользователь знал, что он отключен:

proc exit {args} { error "The exit command is not available in this context" }

Также стоит подумать о запуске кода пользователя в безопасной интерполяции а не в основной оболочке. Это позволит вам точно контролировать, к чему у пользователя есть доступ.

Вы также можете создать дочерний interp (небезопасный) и просто отключить команду выхода для этого interp.

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

namespace eval ::hidden {}
rename exit ::hidden::exit
person RHSeeger    schedule 29.03.2012
comment
Это может сработать. Но все же хотелось бы сохранить «выход». - person ilya1725; 29.03.2012
comment
Если вы хотите, чтобы выход был доступен вам, но не пользователю, я бы порекомендовал безопасный промежуточный маршрут. - person RHSeeger; 29.03.2012
comment
@jk. В общем, я согласен с этим. Очевидное предостережение заключается в том, что он может захотеть предоставить пользователям полную мощь оболочки Tcl, но не хочет, чтобы они случайно вышли из программы. Из вопроса сложно сказать, правда это или нет. - person RHSeeger; 29.03.2012
comment
Да, окончательно последний комментарий: я бы не хотел ограничивать пользователей в том, что они могут печатать. Есть ли способ отправить сигнал ctrl + D в пользовательской процедуре выхода? - person ilya1725; 29.03.2012
comment
Зачем вам нужно отправлять ctrl + D в пользовательской процедуре выхода? Если вы переместите команду выхода в сторону (путем переименования), вы все равно сможете ее вызвать. - person RHSeeger; 29.03.2012

Переименуйте команду exit:

rename exit __exit

proc exit {args} {
    puts -nonewline "Do you really want to exit? (y/n) "
    flush stdout
    gets stdin answer
    if {$answer == "y"} {
        __exit [lindex $args 0]
    }
}

Таким образом, когда пользователь вводит exit, он / она выполнит вашу собственную команду выхода, в которой вы можете делать все, что захотите.

person Hai Vu    schedule 29.03.2012
comment
Спасибо, Хай. Однако это все еще не решает мою проблему - если exit вызывается из Tcl, все мое приложение C закрывается безоговорочно. Мне все еще нужно очистить некоторые ресурсы при выходе. - person ilya1725; 29.03.2012

Использование Tcl_CreateExitHandler отлично работает. Проблема заключалась в том, что я добавил printf в реализацию обработчика, и вывод не отображался на терминале. Так что я подумал, что это не называлось. Однако к моменту выполнения этого обработчика stdout больше не существует. Запуск strace в приложении показывает, что обработчик выполняется нормально.

Другим решением этой проблемы может быть использование atexit и обработка там события выхода.

person ilya1725    schedule 29.03.2012