From d8d6f63a208246d2f1b9366a3c009b0438e84e28 Mon Sep 17 00:00:00 2001 From: dkf Date: Tue, 22 Nov 2005 11:32:35 +0000 Subject: Backport of fixes for [Bug 1353414] --- ChangeLog | 4 ++ generic/tkSelect.c | 27 +++++---- tests/select.test | 17 +++++- unix/tkUnixSelect.c | 166 +++++++++++++++++++++------------------------------- 4 files changed, 103 insertions(+), 111 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9f127e8..b8032fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2005-11-22 Donal K. Fellows + * unix/tkUnixSelect.c (SelCvtToX, SelCvtFromX): Backport of fixes for + * generic/tkSelect.c (TkSelDefaultSelection): "spaces in atom names" + * tests/select.test (select-9.5): problems. [Bug 1353414] + * library/tkfbox.tcl (::tk::dialog::file::): Correct the quoting of the script used in variable traces so that widget names with spaces in will work. [Bug 1335485] diff --git a/generic/tkSelect.c b/generic/tkSelect.c index d62aa43..73e41d8 100644 --- a/generic/tkSelect.c +++ b/generic/tkSelect.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkSelect.c,v 1.13 2003/01/14 19:24:56 jenglish Exp $ + * RCS: @(#) $Id: tkSelect.c,v 1.13.2.1 2005/11/22 11:32:37 dkf Exp $ */ #include "tkInt.h" @@ -1489,29 +1489,32 @@ TkSelDefaultSelection(infoPtr, target, buffer, maxBytes, typePtr) if (target == dispPtr->targetsAtom) { register TkSelHandler *selPtr; - CONST char *atomString; - int length, atomLength; + int length; + Tcl_DString ds; if (maxBytes < 50) { return -1; } - strcpy(buffer, "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW"); - length = strlen(buffer); + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, + "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW", -1); for (selPtr = winPtr->selHandlerList; selPtr != NULL; selPtr = selPtr->nextPtr) { if ((selPtr->selection == infoPtr->selection) && (selPtr->target != dispPtr->applicationAtom) && (selPtr->target != dispPtr->windowAtom)) { - atomString = Tk_GetAtomName((Tk_Window) winPtr, + CONST char *atomString = Tk_GetAtomName((Tk_Window) winPtr, selPtr->target); - atomLength = strlen(atomString) + 1; - if ((length + atomLength) >= maxBytes) { - return -1; - } - sprintf(buffer+length, " %s", atomString); - length += atomLength; + Tcl_DStringAppendElement(&ds, atomString); } } + length = Tcl_DStringLength(&ds); + if (length >= maxBytes) { + Tcl_DStringFree(&ds); + return -1; + } + memcpy(buffer, Tcl_DStringValue(&ds), (unsigned) (1+length)); + Tcl_DStringFree(&ds); *typePtr = XA_ATOM; return length; } diff --git a/tests/select.test b/tests/select.test index 0e24c7c..4e63f9b 100644 --- a/tests/select.test +++ b/tests/select.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: select.test,v 1.9 2002/07/13 20:28:35 dgp Exp $ +# RCS: @(#) $Id: select.test,v 1.9.2.1 2005/11/22 11:32:37 dkf Exp $ # # Note: Multiple display selection handling will only be tested if the @@ -848,6 +848,21 @@ test select-9.4 {SelCvtToX and SelCvtFromX procedures} {unixOnly} { cleanupbg lappend result $selInfo } {{0x10 0x0 0x20} {TEST 0 4000}} +test select-9.5 {SelCvtToX and SelCvtFromX procedures} -setup { + setup + setupbg +} -constraints unix -body { + # Ensure that lists of atoms are constructed correctly, even when the + # atom names have spaces in. [Bug 1353414] + set selValue "foo bar" + set selInfo "" + set selType {text/x-tk-test;detail="foo bar"} + selection handle -selection PRIMARY -format STRING -type $selType \ + .f1 [list handler $selType] + lsort [dobg {selection get TARGETS}] +} -cleanup { + cleanupbg +} -result {MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW {text/x-tk-test;detail="foo bar"}} ############################################################################## diff --git a/unix/tkUnixSelect.c b/unix/tkUnixSelect.c index 92add7f..2592d33 100644 --- a/unix/tkUnixSelect.c +++ b/unix/tkUnixSelect.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixSelect.c,v 1.11 2002/10/01 08:48:08 dkf Exp $ + * RCS: @(#) $Id: tkUnixSelect.c,v 1.11.2.1 2005/11/22 11:32:37 dkf Exp $ */ #include "tkInt.h" @@ -99,8 +99,8 @@ static TkSelRetrievalInfo *pendingRetrievals = NULL; static void ConvertSelection _ANSI_ARGS_((TkWindow *winPtr, XSelectionRequestEvent *eventPtr)); static void IncrTimeoutProc _ANSI_ARGS_((ClientData clientData)); -static char * SelCvtFromX _ANSI_ARGS_((long *propPtr, int numValues, - Atom type, Tk_Window tkwin)); +static void SelCvtFromX _ANSI_ARGS_((long *propPtr, int numValues, + Atom type, Tk_Window tkwin, Tcl_DString *dsPtr)); static long * SelCvtToX _ANSI_ARGS_((char *string, Atom type, Tk_Window tkwin, int *numLongsPtr)); static int SelectionSize _ANSI_ARGS_((TkSelHandler *selPtr)); @@ -461,11 +461,16 @@ TkSelPropProc(eventPtr) formatType, (Tk_Window) incrPtr->winPtr, &numItems); + if (propPtr == NULL) { + numItems = 0; + } XChangeProperty(eventPtr->xproperty.display, eventPtr->xproperty.window, eventPtr->xproperty.atom, formatType, 32, PropModeReplace, (unsigned char *) propPtr, numItems); - ckfree(propPtr); + if (propPtr != NULL) { + ckfree(propPtr); + } } Tk_DeleteErrorHandler(errorHandler); @@ -676,7 +681,7 @@ TkSelEventProc(tkwin, eventPtr) Tk_DeleteEventHandler(tkwin, PropertyChangeMask, SelRcvIncrProc, (ClientData) retrPtr); } else { - char *string; + Tcl_DString ds; if (format != 32) { char buf[64 + TCL_INTEGER_SPACE]; @@ -688,14 +693,15 @@ TkSelEventProc(tkwin, eventPtr) retrPtr->result = TCL_ERROR; return; } - string = SelCvtFromX((long *) propInfo, (int) numItems, type, - (Tk_Window) winPtr); + Tcl_DStringInit(&ds); + SelCvtFromX((long *) propInfo, (int) numItems, type, + (Tk_Window) winPtr, &ds); interp = retrPtr->interp; Tcl_Preserve((ClientData) interp); retrPtr->result = (*retrPtr->proc)(retrPtr->clientData, - interp, string); + interp, Tcl_DStringValue(&ds)); Tcl_Release((ClientData) interp); - ckfree(string); + Tcl_DStringFree(&ds); } XFree(propInfo); return; @@ -1000,6 +1006,9 @@ ConvertSelection(winPtr, eventPtr) } else { propPtr = (char *) SelCvtToX((char *) buffer, type, (Tk_Window) winPtr, &numItems); + if (propPtr == NULL) { + goto refuse; + } format = 32; XChangeProperty(reply.display, reply.requestor, property, type, format, PropModeReplace, @@ -1260,7 +1269,7 @@ SelRcvIncrProc(clientData, eventPtr) } else if (numItems == 0) { retrPtr->result = TCL_OK; } else { - char *string; + Tcl_DString ds; if (format != 32) { char buf[64 + TCL_INTEGER_SPACE]; @@ -1272,19 +1281,21 @@ SelRcvIncrProc(clientData, eventPtr) retrPtr->result = TCL_ERROR; goto done; } - string = SelCvtFromX((long *) propInfo, (int) numItems, type, - (Tk_Window) retrPtr->winPtr); + Tcl_DStringInit(&ds); + SelCvtFromX((long *) propInfo, (int) numItems, type, + (Tk_Window) retrPtr->winPtr, &ds); interp = retrPtr->interp; Tcl_Preserve((ClientData) interp); - result = (*retrPtr->proc)(retrPtr->clientData, interp, string); + result = (*retrPtr->proc)(retrPtr->clientData, interp, + Tcl_DStringValue(&ds)); Tcl_Release((ClientData) interp); + Tcl_DStringFree(&ds); if (result != TCL_OK) { retrPtr->result = result; } - ckfree(string); } - done: + done: XFree(propInfo); retrPtr->idleTime = 0; } @@ -1405,28 +1416,21 @@ SelCvtToX(string, type, tkwin, numLongsPtr) int *numLongsPtr; /* Number of 32-bit words contained in the * result. */ { - register char *p; - char *field; - int numFields; - long *propPtr, *longPtr; -#define MAX_ATOM_NAME_LENGTH 100 - char atomName[MAX_ATOM_NAME_LENGTH+1]; + const char **field; + int numFields, i; + long *propPtr; /* - * The string is assumed to consist of fields separated by spaces. - * The property gets generated by converting each field to an - * integer number, in one of two ways: - * 1. If type is XA_ATOM, convert each field to its corresponding - * atom. - * 2. If type is anything else, convert each field from an ASCII number - * to a 32-bit binary number. + * The string is assumed to consist of fields separated by spaces. The + * property gets generated by converting each field to an integer number, + * in one of two ways: + * 1. If type is XA_ATOM, convert each field to its corresponding atom. + * 2. If type is anything else, convert each field from an ASCII number to + * a 32-bit binary number. */ - numFields = 1; - for (p = string; *p != 0; p++) { - if (isspace(UCHAR(*p))) { - numFields++; - } + if (Tcl_SplitList(NULL, string, &numFields, &field) != TCL_OK) { + return NULL; } propPtr = (long *) ckalloc((unsigned) numFields*sizeof(long)); @@ -1434,34 +1438,27 @@ SelCvtToX(string, type, tkwin, numLongsPtr) * Convert the fields one-by-one. */ - for (longPtr = propPtr, *numLongsPtr = 0, p = string; - ; longPtr++, (*numLongsPtr)++) { - while (isspace(UCHAR(*p))) { - p++; - } - if (*p == 0) { - break; - } - field = p; - while ((*p != 0) && !isspace(UCHAR(*p))) { - p++; - } + for (i=0 ; i MAX_ATOM_NAME_LENGTH) { - length = MAX_ATOM_NAME_LENGTH; - } - strncpy(atomName, field, (unsigned) length); - atomName[length] = 0; - *longPtr = (long) Tk_InternAtom(tkwin, atomName); + propPtr[i] = (long) Tk_InternAtom(tkwin, field[i]); } else { char *dummy; - *longPtr = strtol(field, &dummy, 0); + /* + * If this fails to parse a number, we just plunge on regardless + * anyway. + */ + + propPtr[i] = strtol(field[i], &dummy, 0); } } + + /* + * Release the parsed list. + */ + + ckfree((char *) field); + *numLongsPtr = i; return propPtr; } @@ -1476,9 +1473,8 @@ SelCvtToX(string, type, tkwin, numLongsPtr) * procedure is the inverse of SelCvtToX. * * Results: - * The return value is the string equivalent of "property". It is - * malloc-ed and should be freed by the caller when no longer - * needed. + * The return value (stored in a Tcl_DString) is the string equivalent of + * "property". It is up to the caller to initialize and free the DString. * * Side effects: * None. @@ -1486,60 +1482,34 @@ SelCvtToX(string, type, tkwin, numLongsPtr) *---------------------------------------------------------------------- */ -static char * -SelCvtFromX(propPtr, numValues, type, tkwin) +static void +SelCvtFromX(propPtr, numValues, type, tkwin, dsPtr) register long *propPtr; /* Property value from X. */ int numValues; /* Number of 32-bit values in property. */ Atom type; /* Type of property Should not be * XA_STRING (if so, don't bother calling * this procedure at all). */ Tk_Window tkwin; /* Window to use for atom conversion. */ + Tcl_DString *dsPtr; /* Where to store the converted string. */ { - char *result; - int resultSpace, curSize, fieldSize; - CONST char *atomName; - /* - * Convert each long in the property to a string value, which is - * either the name of an atom (if type is XA_ATOM) or a hexadecimal - * string. Make an initial guess about the size of the result, but - * be prepared to enlarge the result if necessary. + * Convert each long in the property to a string value, which is either + * the name of an atom (if type is XA_ATOM) or a hexadecimal string. We + * build the list in a Tcl_DString because this is easier than trying to + * get the quoting correct ourselves; this is tricky because atoms can + * contain spaces in their names (encountered when the atoms are really + * MIME types). [Bug 1353414] */ - resultSpace = 12*numValues+1; - curSize = 0; - atomName = ""; /* Not needed, but eliminates compiler warning. */ - result = (char *) ckalloc((unsigned) resultSpace); - *result = '\0'; for ( ; numValues > 0; propPtr++, numValues--) { if (type == XA_ATOM) { - atomName = Tk_GetAtomName(tkwin, (Atom) *propPtr); - fieldSize = strlen(atomName) + 1; + Tcl_DStringAppendElement(dsPtr, + Tk_GetAtomName(tkwin, (Atom) *propPtr)); } else { - fieldSize = 12; - } - if (curSize+fieldSize >= resultSpace) { - char *newResult; + char buf[12]; - resultSpace *= 2; - if (curSize+fieldSize >= resultSpace) { - resultSpace = curSize + fieldSize + 1; - } - newResult = (char *) ckalloc((unsigned) resultSpace); - strncpy(newResult, result, (unsigned) curSize); - ckfree(result); - result = newResult; - } - if (curSize != 0) { - result[curSize] = ' '; - curSize++; - } - if (type == XA_ATOM) { - strcpy(result+curSize, atomName); - } else { - sprintf(result+curSize, "0x%x", (unsigned int) *propPtr); + sprintf(buf, "0x%x", (unsigned int) *propPtr); + Tcl_DStringAppendElement(dsPtr, buf); } - curSize += strlen(result+curSize); } - return result; } -- cgit v0.12