diff options
Diffstat (limited to 'generic/tclConfig.c')
| -rw-r--r-- | generic/tclConfig.c | 165 |
1 files changed, 84 insertions, 81 deletions
diff --git a/generic/tclConfig.c b/generic/tclConfig.c index 670807c..0bbac5b 100644 --- a/generic/tclConfig.c +++ b/generic/tclConfig.c @@ -26,21 +26,24 @@ #define ASSOC_KEY "tclPackageAboutDict" /* - * A ClientData struct for the QueryConfig command. Store the two bits + * A ClientData struct for the QueryConfig command. Store the three bits * of data we need; the package name for which we store a config dict, - * and the (Tcl_Interp *) in which it is stored. + * the (Tcl_Interp *) in which it is stored, and the encoding. */ typedef struct QCCD { Tcl_Obj *pkg; Tcl_Interp *interp; + char *encoding; } QCCD; /* * Static functions in this file: */ -static Tcl_ObjCmdProc QueryConfigObjCmd; +static int QueryConfigObjCmd(ClientData clientData, + Tcl_Interp *interp, int objc, + struct Tcl_Obj *CONST *objv); static void QueryConfigDelete(ClientData clientData); static Tcl_Obj * GetConfigDict(Tcl_Interp *interp); static void ConfigDictDeleteProc(ClientData clientData, @@ -66,29 +69,35 @@ void Tcl_RegisterConfig( Tcl_Interp *interp, /* Interpreter the configuration command is * registered in. */ - const char *pkgName, /* Name of the package registering the + CONST char *pkgName, /* Name of the package registering the * embedded configuration. ASCII, thus in * UTF-8 too. */ - const Tcl_Config *configuration, /* Embedded configuration. */ - const char *valEncoding) /* Name of the encoding used to store the + Tcl_Config *configuration, /* Embedded configuration. */ + CONST char *valEncoding) /* Name of the encoding used to store the * configuration values, ASCII, thus UTF-8. */ { + Tcl_Obj *pDB, *pkgDict; Tcl_DString cmdName; - const Tcl_Config *cfg; - Tcl_Encoding venc = Tcl_GetEncoding(NULL, valEncoding); - QCCD *cdPtr = ckalloc(sizeof(QCCD)); + Tcl_Config *cfg; + QCCD *cdPtr = (QCCD *)ckalloc(sizeof(QCCD)); cdPtr->interp = interp; - cdPtr->pkg = Tcl_NewStringObj(pkgName, TCL_STRLEN); + if (valEncoding) { + cdPtr->encoding = ckalloc(strlen(valEncoding)+1); + strcpy(cdPtr->encoding, valEncoding); + } else { + cdPtr->encoding = NULL; + } + cdPtr->pkg = Tcl_NewStringObj(pkgName, -1); /* * Phase I: Adding the provided information to the internal database of - * package meta data. Only if we have an ok encoding. + * package meta data. * * Phase II: Create a command for querying this database, specific to the - * package registerting its configuration. This is the approved interface + * package registering its configuration. This is the approved interface * in TIP 59. In the future a more general interface should be done, as - * followup to TIP 59. Simply because our database is now general across + * follow-up to TIP 59. Simply because our database is now general across * packages, and not a structure tied to one package. * * Note, the created command will have a reference through its clientdata. @@ -101,53 +110,35 @@ Tcl_RegisterConfig( * dictionaries visible at Tcl level. I.e. they are not filled */ - if (venc != NULL) { - Tcl_Obj *pkgDict, *pDB = GetConfigDict(interp); - - /* - * Retrieve package specific configuration... - */ - - if (Tcl_DictObjGet(interp, pDB, cdPtr->pkg, &pkgDict) != TCL_OK - || (pkgDict == NULL)) { - pkgDict = Tcl_NewDictObj(); - } else if (Tcl_IsShared(pkgDict)) { - pkgDict = Tcl_DuplicateObj(pkgDict); - } + pDB = GetConfigDict(interp); - /* - * Extend the package configuration... - */ + /* + * Retrieve package specific configuration... + */ - for (cfg=configuration ; cfg->key!=NULL && cfg->key[0]!='\0' ; cfg++) { - Tcl_DString conv; - const char *convValue = - Tcl_ExternalToUtfDString(venc, cfg->value, TCL_STRLEN, - &conv); - - /* - * We know that the keys are in ASCII/UTF-8, so for them is no - * conversion required. - */ - - Tcl_DictObjPut(interp, pkgDict, - Tcl_NewStringObj(cfg->key, TCL_STRLEN), - Tcl_NewStringObj(convValue, TCL_STRLEN)); - Tcl_DStringFree(&conv); - } + if (Tcl_DictObjGet(interp, pDB, cdPtr->pkg, &pkgDict) != TCL_OK + || (pkgDict == NULL)) { + pkgDict = Tcl_NewDictObj(); + } else if (Tcl_IsShared(pkgDict)) { + pkgDict = Tcl_DuplicateObj(pkgDict); + } - /* - * We're now done with the encoding, so drop it. - */ + /* + * Extend the package configuration... + * We cannot assume that the encodings are initialized, therefore + * store the value as-is in a byte array. See Bug [9b2e636361]. + */ - Tcl_FreeEncoding(venc); + for (cfg=configuration ; cfg->key!=NULL && cfg->key[0]!='\0' ; cfg++) { + Tcl_DictObjPut(interp, pkgDict, Tcl_NewStringObj(cfg->key, -1), + Tcl_NewByteArrayObj((unsigned char *)cfg->value, strlen(cfg->value))); + } - /* - * Write the changes back into the overall database. - */ + /* + * Write the changes back into the overall database. + */ - Tcl_DictObjPut(interp, pDB, cdPtr->pkg, pkgDict); - } + Tcl_DictObjPut(interp, pDB, cdPtr->pkg, pkgDict); /* * Now create the interface command for retrieval of the package @@ -155,8 +146,8 @@ Tcl_RegisterConfig( */ Tcl_DStringInit(&cmdName); - TclDStringAppendLiteral(&cmdName, "::"); - Tcl_DStringAppend(&cmdName, pkgName, TCL_STRLEN); + Tcl_DStringAppend(&cmdName, "::", -1); + Tcl_DStringAppend(&cmdName, pkgName, -1); /* * The incomplete command name is the name of the namespace to place it @@ -173,10 +164,10 @@ Tcl_RegisterConfig( } } - TclDStringAppendLiteral(&cmdName, "::pkgconfig"); + Tcl_DStringAppend(&cmdName, "::pkgconfig", -1); if (Tcl_CreateObjCommand(interp, Tcl_DStringValue(&cmdName), - QueryConfigObjCmd, cdPtr, QueryConfigDelete) == NULL) { + QueryConfigObjCmd, (ClientData) cdPtr, QueryConfigDelete) == NULL) { Tcl_Panic("%s: %s", "Tcl_RegisterConfig", "Unable to create query command for package configuration"); } @@ -205,23 +196,25 @@ static int QueryConfigObjCmd( ClientData clientData, Tcl_Interp *interp, - size_t objc, - struct Tcl_Obj *const *objv) + int objc, + struct Tcl_Obj *CONST *objv) { - QCCD *cdPtr = clientData; + QCCD *cdPtr = (QCCD *) clientData; Tcl_Obj *pkgName = cdPtr->pkg; Tcl_Obj *pDB, *pkgDict, *val, *listPtr; - int index; - size_t n; - static const char *const subcmdStrings[] = { + int n, index; + static CONST char *subcmdStrings[] = { "get", "list", NULL }; enum subcmds { CFG_GET, CFG_LIST }; + Tcl_DString conv; + Tcl_Encoding venc = NULL; + CONST char *value; if ((objc < 2) || (objc > 3)) { - Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?arg?"); + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?argument?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], subcmdStrings, "subcommand", 0, @@ -237,10 +230,7 @@ QueryConfigObjCmd( * present. */ - Tcl_SetObjResult(interp, Tcl_NewStringObj("package not known", - TCL_STRLEN)); - Tcl_SetErrorCode(interp, "TCL", "FATAL", "PKGCFG_BASE", - Tcl_GetString(pkgName), NULL); + Tcl_SetResult(interp, "package not known", TCL_STATIC); return TCL_ERROR; } @@ -253,14 +243,25 @@ QueryConfigObjCmd( if (Tcl_DictObjGet(interp, pkgDict, objv[2], &val) != TCL_OK || val == NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("key not known", - TCL_STRLEN)); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CONFIG", - Tcl_GetString(objv[2]), NULL); + Tcl_SetResult(interp, "key not known", TCL_STATIC); return TCL_ERROR; } - Tcl_SetObjResult(interp, val); + if (cdPtr->encoding) { + venc = Tcl_GetEncoding(interp, cdPtr->encoding); + if (!venc) { + return TCL_ERROR; + } + } + /* + * Value is stored as-is in a byte array, see Bug [9b2e636361], + * so we have to decode it first. + */ + value = (const char *) Tcl_GetByteArrayFromObj(val, &n); + value = Tcl_ExternalToUtfDString(venc, value, n, &conv); + Tcl_SetObjResult(interp, Tcl_NewStringObj(value, + Tcl_DStringLength(&conv))); + Tcl_DStringFree(&conv); return TCL_OK; case CFG_LIST: @@ -273,9 +274,8 @@ QueryConfigObjCmd( listPtr = Tcl_NewListObj(n, NULL); if (!listPtr) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "insufficient memory to create list", TCL_STRLEN)); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); + Tcl_SetResult(interp, "insufficient memory to create list", + TCL_STATIC); return TCL_ERROR; } @@ -321,13 +321,16 @@ static void QueryConfigDelete( ClientData clientData) { - QCCD *cdPtr = clientData; + QCCD *cdPtr = (QCCD *) clientData; Tcl_Obj *pkgName = cdPtr->pkg; Tcl_Obj *pDB = GetConfigDict(cdPtr->interp); Tcl_DictObjRemove(NULL, pDB, pkgName); Tcl_DecrRefCount(pkgName); - ckfree(cdPtr); + if (cdPtr->encoding) { + ckfree((char *)cdPtr->encoding); + } + ckfree((char *)cdPtr); } /* @@ -369,7 +372,7 @@ GetConfigDict( * * This function is associated with the "Package About dict" assoc data * for an interpreter; it is invoked when the interpreter is deleted in - * order to free the information assoicated with any pending error + * order to free the information associated with any pending error * reports. * * Results: @@ -386,7 +389,7 @@ ConfigDictDeleteProc( ClientData clientData, /* Pointer to Tcl_Obj. */ Tcl_Interp *interp) /* Interpreter being deleted. */ { - Tcl_Obj *pDB = clientData; + Tcl_Obj *pDB = (Tcl_Obj *) clientData; Tcl_DecrRefCount(pDB); } |
