summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXHLEvents.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2019-04-16 12:59:45 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2019-04-16 12:59:45 (GMT)
commit2e318c7f021f7401f9503e5ece135d99f29176b3 (patch)
tree03d642e7a5569afe8c6ad18b094794cda34a6409 /macosx/tkMacOSXHLEvents.c
parente6f5cd1f781c75f281413f3cfd8a6b54453f11af (diff)
downloadtk-2e318c7f021f7401f9503e5ece135d99f29176b3.zip
tk-2e318c7f021f7401f9503e5ece135d99f29176b3.tar.gz
tk-2e318c7f021f7401f9503e5ece135d99f29176b3.tar.bz2
Guard against interpreters being killed out from under our feet when calling Tcl.
Diffstat (limited to 'macosx/tkMacOSXHLEvents.c')
-rw-r--r--macosx/tkMacOSXHLEvents.c146
1 files changed, 82 insertions, 64 deletions
diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c
index 9b874a5..8f04e45 100644
--- a/macosx/tkMacOSXHLEvents.c
+++ b/macosx/tkMacOSXHLEvents.c
@@ -33,12 +33,13 @@ typedef struct KillEvent {
* Static functions used only in this file.
*/
-static void tkMacOSXProcessFiles(NSAppleEventDescriptor* event,
- NSAppleEventDescriptor* replyEvent,
- Tcl_Interp *interp,
- const char* procedure);
-static int MissedAnyParameters(const AppleEvent *theEvent);
-static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
+static void tkMacOSXProcessFiles(NSAppleEventDescriptor *event,
+ NSAppleEventDescriptor *replyEvent,
+ Tcl_Interp *interp, const char* procedure);
+static int MissedAnyParameters(const AppleEvent *theEvent);
+static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
+static void RunSimpleTclCommand(Tcl_Interp *interp,
+ const char *command);
#pragma mark TKApplication(TKHLEvents)
@@ -78,55 +79,34 @@ static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- Tcl_Interp *interp = _eventInterp;
-
- if (interp &&
- Tcl_FindCommand(_eventInterp, "::tk::mac::OpenApplication", NULL, 0)){
- int code = Tcl_EvalEx(_eventInterp, "::tk::mac::OpenApplication",
- -1, TCL_EVAL_GLOBAL);
- if (code != TCL_OK) {
- Tcl_BackgroundException(_eventInterp, code);
- }
- }
+ RunSimpleTclCommand(_eventInterp, "::tk::mac::OpenApplication");
}
- (void) handleReopenApplicationEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
[NSApp activateIgnoringOtherApps: YES];
- if (_eventInterp && Tcl_FindCommand(_eventInterp,
- "::tk::mac::ReopenApplication", NULL, 0)) {
- int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ReopenApplication",
- -1, TCL_EVAL_GLOBAL);
- if (code != TCL_OK){
- Tcl_BackgroundException(_eventInterp, code);
- }
- }
+ RunSimpleTclCommand(_eventInterp, "::tk::mac::ReopenApplication");
}
- (void) handleShowPreferencesEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- if (_eventInterp &&
- Tcl_FindCommand(_eventInterp, "::tk::mac::ShowPreferences", NULL, 0)){
- int code = Tcl_EvalEx(_eventInterp, "::tk::mac::ShowPreferences",
- -1, TCL_EVAL_GLOBAL);
- if (code != TCL_OK) {
- Tcl_BackgroundException(_eventInterp, code);
- }
- }
+ RunSimpleTclCommand(_eventInterp, "::tk::mac::ShowPreferences");
}
- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::OpenDocument");
+ tkMacOSXProcessFiles(event, replyEvent, _eventInterp,
+ "::tk::mac::OpenDocument");
}
- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
- tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::PrintDocument");
+ tkMacOSXProcessFiles(event, replyEvent, _eventInterp,
+ "::tk::mac::PrintDocument");
}
- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
@@ -152,64 +132,73 @@ static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
}
err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType,
- NULL, 0, NULL);
+ NULL, 0, NULL);
if (err != noErr) {
sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err);
- AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
- errString, strlen(errString));
+ AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorString,
+ typeChar, errString, strlen(errString));
return;
}
- if (MissedAnyParameters((AppleEvent*)theDesc)) {
+ if (MissedAnyParameters((AppleEvent *) theDesc)) {
sprintf(errString, "AEDoScriptHandler: extra parameters");
- AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
- errString, strlen(errString));
+ AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorString,
+ typeChar, errString, strlen(errString));
return;
}
+ Tcl_Preserve(_eventInterp);
if (initialType == typeFileURL || initialType == typeAlias) {
/*
* The descriptor can be coerced to a file url. Source the file, or
* pass the path as a string argument to ::tk::mac::DoScriptFile if
* that procedure exists.
*/
+
err = AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
- (Ptr) URLBuffer, URL_MAX_LENGTH, &actual);
+ (Ptr) URLBuffer, URL_MAX_LENGTH, &actual);
if (err == noErr && actual > 0){
URLBuffer[actual] = '\0';
NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
NSURL *fileURL = [NSURL URLWithString:urlString];
Tcl_DString command;
+
Tcl_DStringInit(&command);
- if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)){
+ if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)) {
Tcl_DStringAppend(&command, "::tk::mac::DoScriptFile", -1);
} else {
Tcl_DStringAppend(&command, "source", -1);
}
Tcl_DStringAppendElement(&command, [[fileURL path] UTF8String]);
tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
- Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
+ Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
}
- } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
- NULL, 0, &actual)) {
+ } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text,
+ &type, NULL, 0, &actual)) {
if (actual > 0) {
/*
* The descriptor can be coerced to UTF8 text. Evaluate as Tcl, or
* or pass the text as a string argument to ::tk::mac::DoScriptText
* if that procedure exists.
*/
+
char *data = ckalloc(actual + 1);
- if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
- data, actual, NULL)) {
- if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText", NULL, 0)){
+
+ if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text,
+ &type, data, actual, NULL)) {
+ if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText",
+ NULL, 0)) {
Tcl_DString command;
+
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, "::tk::mac::DoScriptText", -1);
Tcl_DStringAppendElement(&command, data);
- tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
- Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
+ tclErr = Tcl_EvalEx(_eventInterp,
+ Tcl_DStringValue(&command),
+ Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
} else {
- tclErr = Tcl_EvalEx(_eventInterp, data, actual, TCL_EVAL_GLOBAL);
+ tclErr = Tcl_EvalEx(_eventInterp, data, actual,
+ TCL_EVAL_GLOBAL);
}
}
ckfree(data);
@@ -224,32 +213,53 @@ static int ReallyKillMe(Tcl_Event *eventPtr, int flags);
typeString[4] = '\0';
sprintf(errString, "AEDoScriptHandler: invalid script type '%s', "
"must be coercable to 'furl' or 'utf8'", typeString);
- AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, errString,
- strlen(errString));
+ AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString,
+ typeChar, errString, strlen(errString));
}
+
/*
* If we ran some Tcl code, put the result in the reply.
*/
+
if (tclErr >= 0) {
int reslen;
const char *result =
- Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen);
+ Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen);
+
if (tclErr == TCL_OK) {
- AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyDirectObject, typeChar,
- result, reslen);
+ AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyDirectObject,
+ typeChar, result, reslen);
} else {
- AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
- result, reslen);
- AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorNumber, typeSInt32,
- (Ptr) &tclErr,sizeof(int));
+ AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorString,
+ typeChar, result, reslen);
+ AEPutParamPtr((AppleEvent *) [replyEvent aeDesc], keyErrorNumber,
+ typeSInt32, (Ptr) &tclErr, sizeof(int));
}
}
+ Tcl_Release(_eventInterp);
return;
}
@end
#pragma mark -
+
+static void
+RunSimpleTclCommand(
+ Tcl_Interp *interp,
+ const char *command)
+{
+ int code;
+ if (interp && Tcl_FindCommand(interp, command, NULL, 0)) {
+ Tcl_Preserve(interp);
+ code = Tcl_EvalEx(interp, command, -1, TCL_EVAL_GLOBAL);
+ if (code != TCL_OK) {
+ Tcl_BackgroundException(interp, code);
+ }
+ Tcl_Release(interp);
+ }
+}
+
/*
*----------------------------------------------------------------------
*
@@ -287,7 +297,8 @@ tkMacOSXProcessFiles(
int code;
/*
- * Do nothing if we don't have an interpreter or the procedure doesn't exist.
+ * Do nothing if we don't have an interpreter or the procedure doesn't
+ * exist.
*/
if (!interp || !Tcl_FindCommand(interp, procedure, NULL, 0)) {
@@ -353,12 +364,14 @@ tkMacOSXProcessFiles(
* Handle the event by evaluating the Tcl expression we constructed.
*/
+ Tcl_Preserve(interp);
code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
Tcl_BackgroundException(interp, code);
}
Tcl_DStringFree(&command);
+ Tcl_Release(interp);
}
/*
@@ -382,7 +395,8 @@ void
TkMacOSXInitAppleEvents(
Tcl_Interp *interp) /* not used */
{
- NSAppleEventManager *aeManager = [NSAppleEventManager sharedAppleEventManager];
+ NSAppleEventManager *aeManager =
+ [NSAppleEventManager sharedAppleEventManager];
static Boolean initialized = FALSE;
if (!initialized) {
@@ -488,8 +502,12 @@ ReallyKillMe(
int flags)
{
Tcl_Interp *interp = ((KillEvent *) eventPtr)->interp;
+
+ Tcl_Preserve(interp);
+
int quit = Tcl_FindCommand(interp, "::tk::mac::Quit", NULL, 0)!=NULL;
- int code = Tcl_EvalEx(interp, quit ? "::tk::mac::Quit" : "exit", -1, TCL_EVAL_GLOBAL);
+ int code = Tcl_EvalEx(interp, quit ? "::tk::mac::Quit" : "exit", -1,
+ TCL_EVAL_GLOBAL);
if (code != TCL_OK) {
/*
@@ -498,6 +516,7 @@ ReallyKillMe(
Tcl_BackgroundException(interp, code);
}
+ Tcl_Release(interp);
return 1;
}
@@ -531,7 +550,6 @@ MissedAnyParameters(
return (err != errAEDescNotFound);
}
-
/*
* Local Variables:
* mode: objc