sl@0: /* sl@0: * tclEncoding.c -- sl@0: * sl@0: * Contains the implementation of the encoding conversion package. sl@0: * sl@0: * Copyright (c) 1996-1998 Sun Microsystems, Inc. sl@0: * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved. sl@0: * sl@0: * See the file "license.terms" for information on usage and redistribution sl@0: * of this file, and for a DISCLAIMER OF ALL WARRANTIES. sl@0: * sl@0: * RCS: @(#) $Id: tclEncoding.c,v 1.16.2.14 2007/02/12 19:25:42 andreas_kupries Exp $ sl@0: */ sl@0: sl@0: #include "tclInt.h" sl@0: #include "tclPort.h" sl@0: #if defined(__SYMBIAN32__) sl@0: #include "tclSymbianGlobals.h" sl@0: #endif sl@0: sl@0: typedef size_t (LengthProc)_ANSI_ARGS_((CONST char *src)); sl@0: sl@0: /* sl@0: * The following data structure represents an encoding, which describes how sl@0: * to convert between various character sets and UTF-8. sl@0: */ sl@0: sl@0: typedef struct Encoding { sl@0: char *name; /* Name of encoding. Malloced because (1) sl@0: * hash table entry that owns this encoding sl@0: * may be freed prior to this encoding being sl@0: * freed, (2) string passed in the sl@0: * Tcl_EncodingType structure may not be sl@0: * persistent. */ sl@0: Tcl_EncodingConvertProc *toUtfProc; sl@0: /* Procedure to convert from external sl@0: * encoding into UTF-8. */ sl@0: Tcl_EncodingConvertProc *fromUtfProc; sl@0: /* Procedure to convert from UTF-8 into sl@0: * external encoding. */ sl@0: Tcl_EncodingFreeProc *freeProc; sl@0: /* If non-NULL, procedure to call when this sl@0: * encoding is deleted. */ sl@0: int nullSize; /* Number of 0x00 bytes that signify sl@0: * end-of-string in this encoding. This sl@0: * number is used to determine the source sl@0: * string length when the srcLen argument is sl@0: * negative. This number can be 1 or 2. */ sl@0: ClientData clientData; /* Arbitrary value associated with encoding sl@0: * type. Passed to conversion procedures. */ sl@0: LengthProc *lengthProc; /* Function to compute length of sl@0: * null-terminated strings in this encoding. sl@0: * If nullSize is 1, this is strlen; if sl@0: * nullSize is 2, this is a function that sl@0: * returns the number of bytes in a 0x0000 sl@0: * terminated string. */ sl@0: int refCount; /* Number of uses of this structure. */ sl@0: Tcl_HashEntry *hPtr; /* Hash table entry that owns this encoding. */ sl@0: } Encoding; sl@0: sl@0: /* sl@0: * The following structure is the clientData for a dynamically-loaded, sl@0: * table-driven encoding created by LoadTableEncoding(). It maps between sl@0: * Unicode and a single-byte, double-byte, or multibyte (1 or 2 bytes only) sl@0: * encoding. sl@0: */ sl@0: sl@0: typedef struct TableEncodingData { sl@0: int fallback; /* Character (in this encoding) to sl@0: * substitute when this encoding cannot sl@0: * represent a UTF-8 character. */ sl@0: char prefixBytes[256]; /* If a byte in the input stream is a lead sl@0: * byte for a 2-byte sequence, the sl@0: * corresponding entry in this array is 1, sl@0: * otherwise it is 0. */ sl@0: unsigned short **toUnicode; /* Two dimensional sparse matrix to map sl@0: * characters from the encoding to Unicode. sl@0: * Each element of the toUnicode array points sl@0: * to an array of 256 shorts. If there is no sl@0: * corresponding character in Unicode, the sl@0: * value in the matrix is 0x0000. malloc'd. */ sl@0: unsigned short **fromUnicode; sl@0: /* Two dimensional sparse matrix to map sl@0: * characters from Unicode to the encoding. sl@0: * Each element of the fromUnicode array sl@0: * points to an array of 256 shorts. If there sl@0: * is no corresponding character the encoding, sl@0: * the value in the matrix is 0x0000. sl@0: * malloc'd. */ sl@0: } TableEncodingData; sl@0: sl@0: /* sl@0: * The following structures is the clientData for a dynamically-loaded, sl@0: * escape-driven encoding that is itself comprised of other simpler sl@0: * encodings. An example is "iso-2022-jp", which uses escape sequences to sl@0: * switch between ascii, jis0208, jis0212, gb2312, and ksc5601. Note that sl@0: * "escape-driven" does not necessarily mean that the ESCAPE character is sl@0: * the character used for switching character sets. sl@0: */ sl@0: sl@0: typedef struct EscapeSubTable { sl@0: unsigned int sequenceLen; /* Length of following string. */ sl@0: char sequence[16]; /* Escape code that marks this encoding. */ sl@0: char name[32]; /* Name for encoding. */ sl@0: Encoding *encodingPtr; /* Encoding loaded using above name, or NULL sl@0: * if this sub-encoding has not been needed sl@0: * yet. */ sl@0: } EscapeSubTable; sl@0: sl@0: typedef struct EscapeEncodingData { sl@0: int fallback; /* Character (in this encoding) to sl@0: * substitute when this encoding cannot sl@0: * represent a UTF-8 character. */ sl@0: unsigned int initLen; /* Length of following string. */ sl@0: char init[16]; /* String to emit or expect before first char sl@0: * in conversion. */ sl@0: unsigned int finalLen; /* Length of following string. */ sl@0: char final[16]; /* String to emit or expect after last char sl@0: * in conversion. */ sl@0: char prefixBytes[256]; /* If a byte in the input stream is the sl@0: * first character of one of the escape sl@0: * sequences in the following array, the sl@0: * corresponding entry in this array is 1, sl@0: * otherwise it is 0. */ sl@0: int numSubTables; /* Length of following array. */ sl@0: EscapeSubTable subTables[1];/* Information about each EscapeSubTable sl@0: * used by this encoding type. The actual sl@0: * size will be as large as necessary to sl@0: * hold all EscapeSubTables. */ sl@0: } EscapeEncodingData; sl@0: sl@0: /* sl@0: * Constants used when loading an encoding file to identify the type of the sl@0: * file. sl@0: */ sl@0: sl@0: #define ENCODING_SINGLEBYTE 0 sl@0: #define ENCODING_DOUBLEBYTE 1 sl@0: #define ENCODING_MULTIBYTE 2 sl@0: #define ENCODING_ESCAPE 3 sl@0: sl@0: #if !defined(__SYMBIAN32__) || !defined(__WINSCW__) sl@0: /* sl@0: * Initialize the default encoding directory. If this variable contains sl@0: * a non NULL value, it will be the first path used to locate the sl@0: * system encoding files. sl@0: */ sl@0: sl@0: char *tclDefaultEncodingDir = NULL; sl@0: sl@0: static int encodingsInitialized = 0; sl@0: sl@0: /* sl@0: * Hash table that keeps track of all loaded Encodings. Keys are sl@0: * the string names that represent the encoding, values are (Encoding *). sl@0: */ sl@0: sl@0: static Tcl_HashTable encodingTable; sl@0: TCL_DECLARE_MUTEX(encodingMutex) sl@0: sl@0: /* sl@0: * The following are used to hold the default and current system encodings. sl@0: * If NULL is passed to one of the conversion routines, the current setting sl@0: * of the system encoding will be used to perform the conversion. sl@0: */ sl@0: sl@0: static Tcl_Encoding defaultEncoding; sl@0: static Tcl_Encoding systemEncoding; sl@0: #endif sl@0: /* sl@0: * The following variable is used in the sparse matrix code for a sl@0: * TableEncoding to represent a page in the table that has no entries. sl@0: */ sl@0: sl@0: static unsigned short emptyPage[256]; sl@0: sl@0: /* sl@0: * Procedures used only in this module. sl@0: */ sl@0: sl@0: static int BinaryProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static void DupEncodingIntRep _ANSI_ARGS_((Tcl_Obj *srcPtr, sl@0: Tcl_Obj *dupPtr)); sl@0: static void EscapeFreeProc _ANSI_ARGS_((ClientData clientData)); sl@0: static int EscapeFromUtfProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static int EscapeToUtfProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static void FreeEncoding _ANSI_ARGS_((Tcl_Encoding encoding)); sl@0: static void FreeEncodingIntRep _ANSI_ARGS_((Tcl_Obj *objPtr)); sl@0: static Encoding * GetTableEncoding _ANSI_ARGS_(( sl@0: EscapeEncodingData *dataPtr, int state)); sl@0: static Tcl_Encoding LoadEncodingFile _ANSI_ARGS_((Tcl_Interp *interp, sl@0: CONST char *name)); sl@0: static Tcl_Encoding LoadTableEncoding _ANSI_ARGS_((Tcl_Interp *interp, sl@0: CONST char *name, int type, Tcl_Channel chan)); sl@0: static Tcl_Encoding LoadEscapeEncoding _ANSI_ARGS_((CONST char *name, sl@0: Tcl_Channel chan)); sl@0: static Tcl_Channel OpenEncodingFile _ANSI_ARGS_((CONST char *dir, sl@0: CONST char *name)); sl@0: static void TableFreeProc _ANSI_ARGS_((ClientData clientData)); sl@0: static int TableFromUtfProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static int TableToUtfProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static size_t unilen _ANSI_ARGS_((CONST char *src)); sl@0: static int UnicodeToUtfProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static int UtfToUnicodeProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static int UtfToUtfProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr, int pureNullMode)); sl@0: static int UtfIntToUtfExtProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static int UtfExtToUtfIntProc _ANSI_ARGS_((ClientData clientData, sl@0: CONST char *src, int srcLen, int flags, sl@0: Tcl_EncodingState *statePtr, char *dst, int dstLen, sl@0: int *srcReadPtr, int *dstWrotePtr, sl@0: int *dstCharsPtr)); sl@0: static int TclFindEncodings _ANSI_ARGS_((CONST char *argv0)); sl@0: sl@0: /* sl@0: * A Tcl_ObjType for holding a cached Tcl_Encoding as the intrep. sl@0: * This should help the lifetime of encodings be more useful. sl@0: * See concerns raised in [Bug 1077262]. sl@0: */ sl@0: sl@0: static Tcl_ObjType EncodingType = { sl@0: "encoding", FreeEncodingIntRep, DupEncodingIntRep, NULL, NULL sl@0: }; sl@0: sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * TclGetEncodingFromObj -- sl@0: * sl@0: * Writes to (*encodingPtr) the Tcl_Encoding value of (*objPtr), sl@0: * if possible, and returns TCL_OK. If no such encoding exists, sl@0: * TCL_ERROR is returned, and if interp is non-NULL, an error message sl@0: * is written there. sl@0: * sl@0: * Results: sl@0: * Standard Tcl return code. sl@0: * sl@0: * Side effects: sl@0: * Caches the Tcl_Encoding value as the internal rep of (*objPtr). sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: int sl@0: TclGetEncodingFromObj(interp, objPtr, encodingPtr) sl@0: Tcl_Interp *interp; sl@0: Tcl_Obj *objPtr; sl@0: Tcl_Encoding *encodingPtr; sl@0: { sl@0: CONST char *name = Tcl_GetString(objPtr); sl@0: if (objPtr->typePtr != &EncodingType) { sl@0: Tcl_Encoding encoding = Tcl_GetEncoding(interp, name); sl@0: sl@0: if (encoding == NULL) { sl@0: return TCL_ERROR; sl@0: } sl@0: if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) { sl@0: objPtr->typePtr->freeIntRepProc(objPtr); sl@0: } sl@0: objPtr->internalRep.otherValuePtr = (VOID *) encoding; sl@0: objPtr->typePtr = &EncodingType; sl@0: } sl@0: *encodingPtr = Tcl_GetEncoding(NULL, name); sl@0: return TCL_OK; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FreeEncodingIntRep -- sl@0: * sl@0: * The Tcl_FreeInternalRepProc for the "encoding" Tcl_ObjType. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: static void sl@0: FreeEncodingIntRep(objPtr) sl@0: Tcl_Obj *objPtr; sl@0: { sl@0: Tcl_FreeEncoding((Tcl_Encoding) objPtr->internalRep.otherValuePtr); sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * DupEncodingIntRep -- sl@0: * sl@0: * The Tcl_DupInternalRepProc for the "encoding" Tcl_ObjType. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: static void sl@0: DupEncodingIntRep(srcPtr, dupPtr) sl@0: Tcl_Obj *srcPtr; sl@0: Tcl_Obj *dupPtr; sl@0: { sl@0: dupPtr->internalRep.otherValuePtr = (VOID *) sl@0: Tcl_GetEncoding(NULL, srcPtr->bytes); sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TclInitEncodingSubsystem -- sl@0: * sl@0: * Initialize all resources used by this subsystem on a per-process sl@0: * basis. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * Depends on the memory, object, and IO subsystems. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: void sl@0: TclInitEncodingSubsystem() sl@0: { sl@0: Tcl_EncodingType type; sl@0: sl@0: Tcl_MutexLock(&encodingMutex); sl@0: Tcl_InitHashTable(&encodingTable, TCL_STRING_KEYS); sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: sl@0: /* sl@0: * Create a few initial encodings. Note that the UTF-8 to UTF-8 sl@0: * translation is not a no-op, because it will turn a stream of sl@0: * improperly formed UTF-8 into a properly formed stream. sl@0: */ sl@0: sl@0: type.encodingName = "identity"; sl@0: type.toUtfProc = BinaryProc; sl@0: type.fromUtfProc = BinaryProc; sl@0: type.freeProc = NULL; sl@0: type.nullSize = 1; sl@0: type.clientData = NULL; sl@0: sl@0: defaultEncoding = Tcl_CreateEncoding(&type); sl@0: systemEncoding = Tcl_GetEncoding(NULL, type.encodingName); sl@0: sl@0: type.encodingName = "utf-8"; sl@0: type.toUtfProc = UtfExtToUtfIntProc; sl@0: type.fromUtfProc = UtfIntToUtfExtProc; sl@0: type.freeProc = NULL; sl@0: type.nullSize = 1; sl@0: type.clientData = NULL; sl@0: Tcl_CreateEncoding(&type); sl@0: sl@0: type.encodingName = "unicode"; sl@0: type.toUtfProc = UnicodeToUtfProc; sl@0: type.fromUtfProc = UtfToUnicodeProc; sl@0: type.freeProc = NULL; sl@0: type.nullSize = 2; sl@0: type.clientData = NULL; sl@0: Tcl_CreateEncoding(&type); sl@0: } sl@0: sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * TclFinalizeEncodingSubsystem -- sl@0: * sl@0: * Release the state associated with the encoding subsystem. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * Frees all of the encodings. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: void sl@0: TclFinalizeEncodingSubsystem() sl@0: { sl@0: Tcl_HashSearch search; sl@0: Tcl_HashEntry *hPtr; sl@0: sl@0: Tcl_MutexLock(&encodingMutex); sl@0: encodingsInitialized = 0; sl@0: FreeEncoding(systemEncoding); sl@0: hPtr = Tcl_FirstHashEntry(&encodingTable, &search); sl@0: while (hPtr != NULL) { sl@0: /* sl@0: * Call FreeEncoding instead of doing it directly to handle refcounts sl@0: * like escape encodings use. [Bug #524674] sl@0: * Make sure to call Tcl_FirstHashEntry repeatedly so that all sl@0: * encodings are eventually cleaned up. sl@0: */ sl@0: FreeEncoding((Tcl_Encoding) Tcl_GetHashValue(hPtr)); sl@0: hPtr = Tcl_FirstHashEntry(&encodingTable, &search); sl@0: } sl@0: Tcl_DeleteHashTable(&encodingTable); sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_GetDefaultEncodingDir -- sl@0: * sl@0: * sl@0: * Results: sl@0: * sl@0: * Side effects: sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C CONST char * sl@0: Tcl_GetDefaultEncodingDir() sl@0: { sl@0: return tclDefaultEncodingDir; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_SetDefaultEncodingDir -- sl@0: * sl@0: * sl@0: * Results: sl@0: * sl@0: * Side effects: sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C void sl@0: Tcl_SetDefaultEncodingDir(path) sl@0: CONST char *path; sl@0: { sl@0: tclDefaultEncodingDir = (char *)ckalloc((unsigned) strlen(path) + 1); sl@0: strcpy(tclDefaultEncodingDir, path); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_GetEncoding -- sl@0: * sl@0: * Given the name of a encoding, find the corresponding Tcl_Encoding sl@0: * token. If the encoding did not already exist, Tcl attempts to sl@0: * dynamically load an encoding by that name. sl@0: * sl@0: * Results: sl@0: * Returns a token that represents the encoding. If the name didn't sl@0: * refer to any known or loadable encoding, NULL is returned. If sl@0: * NULL was returned, an error message is left in interp's result sl@0: * object, unless interp was NULL. sl@0: * sl@0: * Side effects: sl@0: * The new encoding type is entered into a table visible to all sl@0: * interpreters, keyed off the encoding's name. For each call to sl@0: * this procedure, there should eventually be a call to sl@0: * Tcl_FreeEncoding, so that the database can be cleaned up when sl@0: * encodings aren't needed anymore. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C Tcl_Encoding sl@0: Tcl_GetEncoding(interp, name) sl@0: Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ sl@0: CONST char *name; /* The name of the desired encoding. */ sl@0: { sl@0: Tcl_HashEntry *hPtr; sl@0: Encoding *encodingPtr; sl@0: sl@0: Tcl_MutexLock(&encodingMutex); sl@0: if (name == NULL) { sl@0: encodingPtr = (Encoding *) systemEncoding; sl@0: encodingPtr->refCount++; sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: return systemEncoding; sl@0: } sl@0: sl@0: hPtr = Tcl_FindHashEntry(&encodingTable, name); sl@0: if (hPtr != NULL) { sl@0: encodingPtr = (Encoding *) Tcl_GetHashValue(hPtr); sl@0: encodingPtr->refCount++; sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: return (Tcl_Encoding) encodingPtr; sl@0: } sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: return LoadEncodingFile(interp, name); sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_FreeEncoding -- sl@0: * sl@0: * This procedure is called to release an encoding allocated by sl@0: * Tcl_CreateEncoding() or Tcl_GetEncoding(). sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * The reference count associated with the encoding is decremented sl@0: * and the encoding may be deleted if nothing is using it anymore. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C void sl@0: Tcl_FreeEncoding(encoding) sl@0: Tcl_Encoding encoding; sl@0: { sl@0: Tcl_MutexLock(&encodingMutex); sl@0: FreeEncoding(encoding); sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * FreeEncoding -- sl@0: * sl@0: * This procedure is called to release an encoding by procedures sl@0: * that already have the encodingMutex. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * The reference count associated with the encoding is decremented sl@0: * and the encoding may be deleted if nothing is using it anymore. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static void sl@0: FreeEncoding(encoding) sl@0: Tcl_Encoding encoding; sl@0: { sl@0: Encoding *encodingPtr; sl@0: sl@0: encodingPtr = (Encoding *) encoding; sl@0: if (encodingPtr == NULL) { sl@0: return; sl@0: } sl@0: encodingPtr->refCount--; sl@0: if (encodingPtr->refCount == 0) { sl@0: if (encodingPtr->freeProc != NULL) { sl@0: (*encodingPtr->freeProc)(encodingPtr->clientData); sl@0: } sl@0: if (encodingPtr->hPtr != NULL) { sl@0: Tcl_DeleteHashEntry(encodingPtr->hPtr); sl@0: } sl@0: ckfree((char *) encodingPtr->name); sl@0: ckfree((char *) encodingPtr); sl@0: } sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_GetEncodingName -- sl@0: * sl@0: * Given an encoding, return the name that was used to constuct sl@0: * the encoding. sl@0: * sl@0: * Results: sl@0: * The name of the encoding. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C CONST char * sl@0: Tcl_GetEncodingName(encoding) sl@0: Tcl_Encoding encoding; /* The encoding whose name to fetch. */ sl@0: { sl@0: Encoding *encodingPtr; sl@0: sl@0: if (encoding == NULL) { sl@0: encoding = systemEncoding; sl@0: } sl@0: encodingPtr = (Encoding *) encoding; sl@0: return encodingPtr->name; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_GetEncodingNames -- sl@0: * sl@0: * Get the list of all known encodings, including the ones stored sl@0: * as files on disk in the encoding path. sl@0: * sl@0: * Results: sl@0: * Modifies interp's result object to hold a list of all the available sl@0: * encodings. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C void sl@0: Tcl_GetEncodingNames(interp) sl@0: Tcl_Interp *interp; /* Interp to hold result. */ sl@0: { sl@0: Tcl_HashSearch search; sl@0: Tcl_HashEntry *hPtr; sl@0: Tcl_Obj *pathPtr, *resultPtr; sl@0: int dummy; sl@0: sl@0: Tcl_HashTable table; sl@0: sl@0: Tcl_MutexLock(&encodingMutex); sl@0: Tcl_InitHashTable(&table, TCL_STRING_KEYS); sl@0: hPtr = Tcl_FirstHashEntry(&encodingTable, &search); sl@0: while (hPtr != NULL) { sl@0: Encoding *encodingPtr; sl@0: sl@0: encodingPtr = (Encoding *) Tcl_GetHashValue(hPtr); sl@0: Tcl_CreateHashEntry(&table, encodingPtr->name, &dummy); sl@0: hPtr = Tcl_NextHashEntry(&search); sl@0: } sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: sl@0: pathPtr = TclGetLibraryPath(); sl@0: if (pathPtr != NULL) { sl@0: int i, objc; sl@0: Tcl_Obj **objv; sl@0: char globArgString[10]; sl@0: Tcl_Obj* encodingObj = Tcl_NewStringObj("encoding",-1); sl@0: Tcl_IncrRefCount(encodingObj); sl@0: sl@0: objc = 0; sl@0: Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv); sl@0: sl@0: for (i = 0; i < objc; i++) { sl@0: Tcl_Obj *searchIn; sl@0: sl@0: /* sl@0: * Construct the path from the element of pathPtr, sl@0: * joined with 'encoding'. sl@0: */ sl@0: searchIn = Tcl_FSJoinToPath(objv[i],1,&encodingObj); sl@0: Tcl_IncrRefCount(searchIn); sl@0: Tcl_ResetResult(interp); sl@0: sl@0: /* sl@0: * TclGlob() changes the contents of globArgString, which causes sl@0: * a segfault if we pass in a pointer to non-writeable memory. sl@0: * TclGlob() puts its results directly into interp. sl@0: */ sl@0: sl@0: strcpy(globArgString, "*.enc"); sl@0: /* sl@0: * The GLOBMODE_TAILS flag returns just the tail of each file sl@0: * which is the encoding name with a .enc extension sl@0: */ sl@0: if ((TclGlob(interp, globArgString, searchIn, sl@0: TCL_GLOBMODE_TAILS, NULL) == TCL_OK)) { sl@0: int objc2 = 0; sl@0: Tcl_Obj **objv2; sl@0: int j; sl@0: sl@0: Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), &objc2, sl@0: &objv2); sl@0: sl@0: for (j = 0; j < objc2; j++) { sl@0: int length; sl@0: char *string; sl@0: string = Tcl_GetStringFromObj(objv2[j], &length); sl@0: length -= 4; sl@0: if (length > 0) { sl@0: string[length] = '\0'; sl@0: Tcl_CreateHashEntry(&table, string, &dummy); sl@0: string[length] = '.'; sl@0: } sl@0: } sl@0: } sl@0: Tcl_DecrRefCount(searchIn); sl@0: } sl@0: Tcl_DecrRefCount(encodingObj); sl@0: } sl@0: sl@0: /* sl@0: * Clear any values placed in the result by globbing. sl@0: */ sl@0: sl@0: Tcl_ResetResult(interp); sl@0: resultPtr = Tcl_GetObjResult(interp); sl@0: sl@0: hPtr = Tcl_FirstHashEntry(&table, &search); sl@0: while (hPtr != NULL) { sl@0: Tcl_Obj *strPtr; sl@0: sl@0: strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&table, hPtr), -1); sl@0: Tcl_ListObjAppendElement(NULL, resultPtr, strPtr); sl@0: hPtr = Tcl_NextHashEntry(&search); sl@0: } sl@0: Tcl_DeleteHashTable(&table); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------ sl@0: * sl@0: * Tcl_SetSystemEncoding -- sl@0: * sl@0: * Sets the default encoding that should be used whenever the user sl@0: * passes a NULL value in to one of the conversion routines. sl@0: * If the supplied name is NULL, the system encoding is reset to the sl@0: * default system encoding. sl@0: * sl@0: * Results: sl@0: * The return value is TCL_OK if the system encoding was successfully sl@0: * set to the encoding specified by name, TCL_ERROR otherwise. If sl@0: * TCL_ERROR is returned, an error message is left in interp's result sl@0: * object, unless interp was NULL. sl@0: * sl@0: * Side effects: sl@0: * The reference count of the new system encoding is incremented. sl@0: * The reference count of the old system encoding is decremented and sl@0: * it may be freed. sl@0: * sl@0: *------------------------------------------------------------------------ sl@0: */ sl@0: sl@0: EXPORT_C int sl@0: Tcl_SetSystemEncoding(interp, name) sl@0: Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ sl@0: CONST char *name; /* The name of the desired encoding, or NULL sl@0: * to reset to default encoding. */ sl@0: { sl@0: Tcl_Encoding encoding; sl@0: Encoding *encodingPtr; sl@0: sl@0: if (name == NULL) { sl@0: Tcl_MutexLock(&encodingMutex); sl@0: encoding = defaultEncoding; sl@0: encodingPtr = (Encoding *) encoding; sl@0: encodingPtr->refCount++; sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: } else { sl@0: encoding = Tcl_GetEncoding(interp, name); sl@0: if (encoding == NULL) { sl@0: return TCL_ERROR; sl@0: } sl@0: } sl@0: sl@0: Tcl_MutexLock(&encodingMutex); sl@0: FreeEncoding(systemEncoding); sl@0: systemEncoding = encoding; sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: sl@0: return TCL_OK; sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_CreateEncoding -- sl@0: * sl@0: * This procedure is called to define a new encoding and the procedures sl@0: * that are used to convert between the specified encoding and Unicode. sl@0: * sl@0: * Results: sl@0: * Returns a token that represents the encoding. If an encoding with sl@0: * the same name already existed, the old encoding token remains sl@0: * valid and continues to behave as it used to, and will eventually sl@0: * be garbage collected when the last reference to it goes away. Any sl@0: * subsequent calls to Tcl_GetEncoding with the specified name will sl@0: * retrieve the most recent encoding token. sl@0: * sl@0: * Side effects: sl@0: * The new encoding type is entered into a table visible to all sl@0: * interpreters, keyed off the encoding's name. For each call to sl@0: * this procedure, there should eventually be a call to sl@0: * Tcl_FreeEncoding, so that the database can be cleaned up when sl@0: * encodings aren't needed anymore. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C Tcl_Encoding sl@0: Tcl_CreateEncoding(typePtr) sl@0: Tcl_EncodingType *typePtr; /* The encoding type. */ sl@0: { sl@0: Tcl_HashEntry *hPtr; sl@0: int new; sl@0: Encoding *encodingPtr; sl@0: char *name; sl@0: sl@0: Tcl_MutexLock(&encodingMutex); sl@0: hPtr = Tcl_CreateHashEntry(&encodingTable, typePtr->encodingName, &new); sl@0: if (new == 0) { sl@0: /* sl@0: * Remove old encoding from hash table, but don't delete it until sl@0: * last reference goes away. sl@0: */ sl@0: sl@0: encodingPtr = (Encoding *) Tcl_GetHashValue(hPtr); sl@0: encodingPtr->hPtr = NULL; sl@0: } sl@0: sl@0: name = ckalloc((unsigned) strlen(typePtr->encodingName) + 1); sl@0: sl@0: encodingPtr = (Encoding *) ckalloc(sizeof(Encoding)); sl@0: encodingPtr->name = strcpy(name, typePtr->encodingName); sl@0: encodingPtr->toUtfProc = typePtr->toUtfProc; sl@0: encodingPtr->fromUtfProc = typePtr->fromUtfProc; sl@0: encodingPtr->freeProc = typePtr->freeProc; sl@0: encodingPtr->nullSize = typePtr->nullSize; sl@0: encodingPtr->clientData = typePtr->clientData; sl@0: if (typePtr->nullSize == 1) { sl@0: encodingPtr->lengthProc = (LengthProc *) strlen; sl@0: } else { sl@0: encodingPtr->lengthProc = (LengthProc *) unilen; sl@0: } sl@0: encodingPtr->refCount = 1; sl@0: encodingPtr->hPtr = hPtr; sl@0: Tcl_SetHashValue(hPtr, encodingPtr); sl@0: sl@0: Tcl_MutexUnlock(&encodingMutex); sl@0: sl@0: return (Tcl_Encoding) encodingPtr; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_ExternalToUtfDString -- sl@0: * sl@0: * Convert a source buffer from the specified encoding into UTF-8. sl@0: * If any of the bytes in the source buffer are invalid or cannot sl@0: * be represented in the target encoding, a default fallback sl@0: * character will be substituted. sl@0: * sl@0: * Results: sl@0: * The converted bytes are stored in the DString, which is then NULL sl@0: * terminated. The return value is a pointer to the value stored sl@0: * in the DString. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C char * sl@0: Tcl_ExternalToUtfDString(encoding, src, srcLen, dstPtr) sl@0: Tcl_Encoding encoding; /* The encoding for the source string, or sl@0: * NULL for the default system encoding. */ sl@0: CONST char *src; /* Source string in specified encoding. */ sl@0: int srcLen; /* Source string length in bytes, or < 0 for sl@0: * encoding-specific string length. */ sl@0: Tcl_DString *dstPtr; /* Uninitialized or free DString in which sl@0: * the converted string is stored. */ sl@0: { sl@0: char *dst; sl@0: Tcl_EncodingState state; sl@0: Encoding *encodingPtr; sl@0: int flags, dstLen, result, soFar, srcRead, dstWrote, dstChars; sl@0: sl@0: Tcl_DStringInit(dstPtr); sl@0: dst = Tcl_DStringValue(dstPtr); sl@0: dstLen = dstPtr->spaceAvl - 1; sl@0: sl@0: if (encoding == NULL) { sl@0: encoding = systemEncoding; sl@0: } sl@0: encodingPtr = (Encoding *) encoding; sl@0: sl@0: if (src == NULL) { sl@0: srcLen = 0; sl@0: } else if (srcLen < 0) { sl@0: srcLen = (*encodingPtr->lengthProc)(src); sl@0: } sl@0: flags = TCL_ENCODING_START | TCL_ENCODING_END; sl@0: while (1) { sl@0: result = (*encodingPtr->toUtfProc)(encodingPtr->clientData, src, sl@0: srcLen, flags, &state, dst, dstLen, &srcRead, &dstWrote, sl@0: &dstChars); sl@0: soFar = dst + dstWrote - Tcl_DStringValue(dstPtr); sl@0: if (result != TCL_CONVERT_NOSPACE) { sl@0: Tcl_DStringSetLength(dstPtr, soFar); sl@0: return Tcl_DStringValue(dstPtr); sl@0: } sl@0: flags &= ~TCL_ENCODING_START; sl@0: src += srcRead; sl@0: srcLen -= srcRead; sl@0: if (Tcl_DStringLength(dstPtr) == 0) { sl@0: Tcl_DStringSetLength(dstPtr, dstLen); sl@0: } sl@0: Tcl_DStringSetLength(dstPtr, 2 * Tcl_DStringLength(dstPtr) + 1); sl@0: dst = Tcl_DStringValue(dstPtr) + soFar; sl@0: dstLen = Tcl_DStringLength(dstPtr) - soFar - 1; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_ExternalToUtf -- sl@0: * sl@0: * Convert a source buffer from the specified encoding into UTF-8. sl@0: * sl@0: * Results: sl@0: * The return value is one of TCL_OK, TCL_CONVERT_MULTIBYTE, sl@0: * TCL_CONVERT_SYNTAX, TCL_CONVERT_UNKNOWN, or TCL_CONVERT_NOSPACE, sl@0: * as documented in tcl.h. sl@0: * sl@0: * Side effects: sl@0: * The converted bytes are stored in the output buffer. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C int sl@0: Tcl_ExternalToUtf(interp, encoding, src, srcLen, flags, statePtr, dst, sl@0: dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: Tcl_Interp *interp; /* Interp for error return, if not NULL. */ sl@0: Tcl_Encoding encoding; /* The encoding for the source string, or sl@0: * NULL for the default system encoding. */ sl@0: CONST char *src; /* Source string in specified encoding. */ sl@0: int srcLen; /* Source string length in bytes, or < 0 for sl@0: * encoding-specific string length. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: Encoding *encodingPtr; sl@0: int result, srcRead, dstWrote, dstChars; sl@0: Tcl_EncodingState state; sl@0: sl@0: if (encoding == NULL) { sl@0: encoding = systemEncoding; sl@0: } sl@0: encodingPtr = (Encoding *) encoding; sl@0: sl@0: if (src == NULL) { sl@0: srcLen = 0; sl@0: } else if (srcLen < 0) { sl@0: srcLen = (*encodingPtr->lengthProc)(src); sl@0: } sl@0: if (statePtr == NULL) { sl@0: flags |= TCL_ENCODING_START | TCL_ENCODING_END; sl@0: statePtr = &state; sl@0: } sl@0: if (srcReadPtr == NULL) { sl@0: srcReadPtr = &srcRead; sl@0: } sl@0: if (dstWrotePtr == NULL) { sl@0: dstWrotePtr = &dstWrote; sl@0: } sl@0: if (dstCharsPtr == NULL) { sl@0: dstCharsPtr = &dstChars; sl@0: } sl@0: sl@0: /* sl@0: * If there are any null characters in the middle of the buffer, they will sl@0: * converted to the UTF-8 null character (\xC080). To get the actual sl@0: * \0 at the end of the destination buffer, we need to append it manually. sl@0: */ sl@0: sl@0: dstLen--; sl@0: result = (*encodingPtr->toUtfProc)(encodingPtr->clientData, src, srcLen, sl@0: flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, sl@0: dstCharsPtr); sl@0: dst[*dstWrotePtr] = '\0'; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_UtfToExternalDString -- sl@0: * sl@0: * Convert a source buffer from UTF-8 into the specified encoding. sl@0: * If any of the bytes in the source buffer are invalid or cannot sl@0: * be represented in the target encoding, a default fallback sl@0: * character will be substituted. sl@0: * sl@0: * Results: sl@0: * The converted bytes are stored in the DString, which is then sl@0: * NULL terminated in an encoding-specific manner. The return value sl@0: * is a pointer to the value stored in the DString. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C char * sl@0: Tcl_UtfToExternalDString(encoding, src, srcLen, dstPtr) sl@0: Tcl_Encoding encoding; /* The encoding for the converted string, sl@0: * or NULL for the default system encoding. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes, or < 0 for sl@0: * strlen(). */ sl@0: Tcl_DString *dstPtr; /* Uninitialized or free DString in which sl@0: * the converted string is stored. */ sl@0: { sl@0: char *dst; sl@0: Tcl_EncodingState state; sl@0: Encoding *encodingPtr; sl@0: int flags, dstLen, result, soFar, srcRead, dstWrote, dstChars; sl@0: sl@0: Tcl_DStringInit(dstPtr); sl@0: dst = Tcl_DStringValue(dstPtr); sl@0: dstLen = dstPtr->spaceAvl - 1; sl@0: sl@0: if (encoding == NULL) { sl@0: encoding = systemEncoding; sl@0: } sl@0: encodingPtr = (Encoding *) encoding; sl@0: sl@0: if (src == NULL) { sl@0: srcLen = 0; sl@0: } else if (srcLen < 0) { sl@0: srcLen = strlen(src); sl@0: } sl@0: flags = TCL_ENCODING_START | TCL_ENCODING_END; sl@0: while (1) { sl@0: result = (*encodingPtr->fromUtfProc)(encodingPtr->clientData, src, sl@0: srcLen, flags, &state, dst, dstLen, &srcRead, &dstWrote, sl@0: &dstChars); sl@0: soFar = dst + dstWrote - Tcl_DStringValue(dstPtr); sl@0: if (result != TCL_CONVERT_NOSPACE) { sl@0: if (encodingPtr->nullSize == 2) { sl@0: Tcl_DStringSetLength(dstPtr, soFar + 1); sl@0: } sl@0: Tcl_DStringSetLength(dstPtr, soFar); sl@0: return Tcl_DStringValue(dstPtr); sl@0: } sl@0: flags &= ~TCL_ENCODING_START; sl@0: src += srcRead; sl@0: srcLen -= srcRead; sl@0: if (Tcl_DStringLength(dstPtr) == 0) { sl@0: Tcl_DStringSetLength(dstPtr, dstLen); sl@0: } sl@0: Tcl_DStringSetLength(dstPtr, 2 * Tcl_DStringLength(dstPtr) + 1); sl@0: dst = Tcl_DStringValue(dstPtr) + soFar; sl@0: dstLen = Tcl_DStringLength(dstPtr) - soFar - 1; sl@0: } sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_UtfToExternal -- sl@0: * sl@0: * Convert a buffer from UTF-8 into the specified encoding. sl@0: * sl@0: * Results: sl@0: * The return value is one of TCL_OK, TCL_CONVERT_MULTIBYTE, sl@0: * TCL_CONVERT_SYNTAX, TCL_CONVERT_UNKNOWN, or TCL_CONVERT_NOSPACE, sl@0: * as documented in tcl.h. sl@0: * sl@0: * Side effects: sl@0: * The converted bytes are stored in the output buffer. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C int sl@0: Tcl_UtfToExternal(interp, encoding, src, srcLen, flags, statePtr, dst, sl@0: dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: Tcl_Interp *interp; /* Interp for error return, if not NULL. */ sl@0: Tcl_Encoding encoding; /* The encoding for the converted string, sl@0: * or NULL for the default system encoding. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes, or < 0 for sl@0: * strlen(). */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: Encoding *encodingPtr; sl@0: int result, srcRead, dstWrote, dstChars; sl@0: Tcl_EncodingState state; sl@0: sl@0: if (encoding == NULL) { sl@0: encoding = systemEncoding; sl@0: } sl@0: encodingPtr = (Encoding *) encoding; sl@0: sl@0: if (src == NULL) { sl@0: srcLen = 0; sl@0: } else if (srcLen < 0) { sl@0: srcLen = strlen(src); sl@0: } sl@0: if (statePtr == NULL) { sl@0: flags |= TCL_ENCODING_START | TCL_ENCODING_END; sl@0: statePtr = &state; sl@0: } sl@0: if (srcReadPtr == NULL) { sl@0: srcReadPtr = &srcRead; sl@0: } sl@0: if (dstWrotePtr == NULL) { sl@0: dstWrotePtr = &dstWrote; sl@0: } sl@0: if (dstCharsPtr == NULL) { sl@0: dstCharsPtr = &dstChars; sl@0: } sl@0: sl@0: dstLen -= encodingPtr->nullSize; sl@0: result = (*encodingPtr->fromUtfProc)(encodingPtr->clientData, src, srcLen, sl@0: flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, sl@0: dstCharsPtr); sl@0: if (encodingPtr->nullSize == 2) { sl@0: dst[*dstWrotePtr + 1] = '\0'; sl@0: } sl@0: dst[*dstWrotePtr] = '\0'; sl@0: sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * Tcl_FindExecutable -- sl@0: * sl@0: * This procedure computes the absolute path name of the current sl@0: * application, given its argv[0] value. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * The variable tclExecutableName gets filled in with the file sl@0: * name for the application, if we figured it out. If we couldn't sl@0: * figure it out, tclExecutableName is set to NULL. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: EXPORT_C void sl@0: Tcl_FindExecutable(argv0) sl@0: CONST char *argv0; /* The value of the application's argv[0] sl@0: * (native). */ sl@0: { sl@0: int mustCleanUtf; sl@0: CONST char *name; sl@0: Tcl_DString buffer, nameString; sl@0: sl@0: TclInitSubsystems(argv0); sl@0: sl@0: if (argv0 == NULL) { sl@0: goto done; sl@0: } sl@0: if (tclExecutableName != NULL) { sl@0: ckfree(tclExecutableName); sl@0: tclExecutableName = NULL; sl@0: } sl@0: if ((name = TclpFindExecutable(argv0)) == NULL) { sl@0: goto done; sl@0: } sl@0: sl@0: /* sl@0: * The value returned from TclpNameOfExecutable is a UTF string that sl@0: * is possibly dirty depending on when it was initialized. sl@0: * TclFindEncodings will indicate whether we must "clean" the UTF (as sl@0: * reported by the underlying system). To assure that the UTF string sl@0: * is a properly encoded native string for this system, convert the sl@0: * UTF string to the default native encoding before the default sl@0: * encoding is initialized. Then, convert it back to UTF after the sl@0: * system encoding is loaded. sl@0: */ sl@0: sl@0: Tcl_UtfToExternalDString(NULL, name, -1, &buffer); sl@0: mustCleanUtf = TclFindEncodings(argv0); sl@0: sl@0: /* sl@0: * Now it is OK to convert the native string back to UTF and set sl@0: * the value of the tclExecutableName. sl@0: */ sl@0: sl@0: if (mustCleanUtf) { sl@0: Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buffer), -1, sl@0: &nameString); sl@0: tclExecutableName = (char *) sl@0: ckalloc((unsigned) (Tcl_DStringLength(&nameString) + 1)); sl@0: strcpy(tclExecutableName, Tcl_DStringValue(&nameString)); sl@0: sl@0: Tcl_DStringFree(&nameString); sl@0: } else { sl@0: tclExecutableName = (char *) ckalloc((unsigned) (strlen(name) + 1)); sl@0: strcpy(tclExecutableName, name); sl@0: } sl@0: Tcl_DStringFree(&buffer); sl@0: return; sl@0: sl@0: done: sl@0: (void) TclFindEncodings(argv0); sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * LoadEncodingFile -- sl@0: * sl@0: * Read a file that describes an encoding and create a new Encoding sl@0: * from the data. sl@0: * sl@0: * Results: sl@0: * The return value is the newly loaded Encoding, or NULL if sl@0: * the file didn't exist of was in the incorrect format. If NULL was sl@0: * returned, an error message is left in interp's result object, sl@0: * unless interp was NULL. sl@0: * sl@0: * Side effects: sl@0: * File read from disk. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static Tcl_Encoding sl@0: LoadEncodingFile(interp, name) sl@0: Tcl_Interp *interp; /* Interp for error reporting, if not NULL. */ sl@0: CONST char *name; /* The name of the encoding file on disk sl@0: * and also the name for new encoding. */ sl@0: { sl@0: int objc, i, ch; sl@0: Tcl_Obj **objv; sl@0: Tcl_Obj *pathPtr; sl@0: Tcl_Channel chan; sl@0: Tcl_Encoding encoding; sl@0: sl@0: pathPtr = TclGetLibraryPath(); sl@0: if (pathPtr == NULL) { sl@0: goto unknown; sl@0: } sl@0: objc = 0; sl@0: Tcl_ListObjGetElements(NULL, pathPtr, &objc, &objv); sl@0: sl@0: chan = NULL; sl@0: for (i = 0; i < objc; i++) { sl@0: chan = OpenEncodingFile(Tcl_GetString(objv[i]), name); sl@0: if (chan != NULL) { sl@0: break; sl@0: } sl@0: } sl@0: sl@0: if (chan == NULL) { sl@0: goto unknown; sl@0: } sl@0: sl@0: Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8"); sl@0: sl@0: while (1) { sl@0: Tcl_DString ds; sl@0: sl@0: Tcl_DStringInit(&ds); sl@0: Tcl_Gets(chan, &ds); sl@0: ch = Tcl_DStringValue(&ds)[0]; sl@0: Tcl_DStringFree(&ds); sl@0: if (ch != '#') { sl@0: break; sl@0: } sl@0: } sl@0: sl@0: encoding = NULL; sl@0: switch (ch) { sl@0: case 'S': { sl@0: encoding = LoadTableEncoding(interp, name, ENCODING_SINGLEBYTE, sl@0: chan); sl@0: break; sl@0: } sl@0: case 'D': { sl@0: encoding = LoadTableEncoding(interp, name, ENCODING_DOUBLEBYTE, sl@0: chan); sl@0: break; sl@0: } sl@0: case 'M': { sl@0: encoding = LoadTableEncoding(interp, name, ENCODING_MULTIBYTE, sl@0: chan); sl@0: break; sl@0: } sl@0: case 'E': { sl@0: encoding = LoadEscapeEncoding(name, chan); sl@0: break; sl@0: } sl@0: } sl@0: if ((encoding == NULL) && (interp != NULL)) { sl@0: Tcl_AppendResult(interp, "invalid encoding file \"", name, "\"", NULL); sl@0: if (ch == 'E') { sl@0: Tcl_AppendResult(interp, " or missing sub-encoding", NULL); sl@0: } sl@0: } sl@0: Tcl_Close(NULL, chan); sl@0: return encoding; sl@0: sl@0: unknown: sl@0: if (interp != NULL) { sl@0: Tcl_AppendResult(interp, "unknown encoding \"", name, "\"", NULL); sl@0: } sl@0: return NULL; sl@0: } sl@0: sl@0: /* sl@0: *---------------------------------------------------------------------- sl@0: * sl@0: * OpenEncodingFile -- sl@0: * sl@0: * Look for the file encoding/.enc in the specified sl@0: * directory. sl@0: * sl@0: * Results: sl@0: * Returns an open file channel if the file exists. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *---------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static Tcl_Channel sl@0: OpenEncodingFile(dir, name) sl@0: CONST char *dir; sl@0: CONST char *name; sl@0: sl@0: { sl@0: CONST char *argv[3]; sl@0: Tcl_DString pathString; sl@0: CONST char *path; sl@0: Tcl_Channel chan; sl@0: Tcl_Obj *pathPtr; sl@0: sl@0: argv[0] = dir; sl@0: argv[1] = "encoding"; sl@0: argv[2] = name; sl@0: sl@0: Tcl_DStringInit(&pathString); sl@0: Tcl_JoinPath(3, argv, &pathString); sl@0: path = Tcl_DStringAppend(&pathString, ".enc", -1); sl@0: pathPtr = Tcl_NewStringObj(path,-1); sl@0: sl@0: Tcl_IncrRefCount(pathPtr); sl@0: chan = Tcl_FSOpenFileChannel(NULL, pathPtr, "r", 0); sl@0: Tcl_DecrRefCount(pathPtr); sl@0: sl@0: Tcl_DStringFree(&pathString); sl@0: sl@0: return chan; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * LoadTableEncoding -- sl@0: * sl@0: * Helper function for LoadEncodingTable(). Loads a table to that sl@0: * converts between Unicode and some other encoding and creates an sl@0: * encoding (using a TableEncoding structure) from that information. sl@0: * sl@0: * File contains binary data, but begins with a marker to indicate sl@0: * byte-ordering, so that same binary file can be read on either sl@0: * endian platforms. sl@0: * sl@0: * Results: sl@0: * The return value is the new encoding, or NULL if the encoding sl@0: * could not be created (because the file contained invalid data). sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static Tcl_Encoding sl@0: LoadTableEncoding(interp, name, type, chan) sl@0: Tcl_Interp *interp; /* Interp for temporary obj while reading. */ sl@0: CONST char *name; /* Name for new encoding. */ sl@0: int type; /* Type of encoding (ENCODING_?????). */ sl@0: Tcl_Channel chan; /* File containing new encoding. */ sl@0: { sl@0: Tcl_DString lineString; sl@0: Tcl_Obj *objPtr; sl@0: char *line; sl@0: int i, hi, lo, numPages, symbol, fallback; sl@0: unsigned char used[256]; sl@0: unsigned int size; sl@0: TableEncodingData *dataPtr; sl@0: unsigned short *pageMemPtr; sl@0: Tcl_EncodingType encType; sl@0: sl@0: /* sl@0: * Speed over memory. Use a full 256 character table to decode hex sl@0: * sequences in the encoding files. sl@0: */ sl@0: sl@0: static char staticHex[] = { sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 ... 15 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 ... 31 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 ... 47 */ sl@0: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 48 ... 63 */ sl@0: 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 ... 79 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 ... 95 */ sl@0: 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 ... 111 */ sl@0: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 112 ... 127 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 ... 143 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 ... 159 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 ... 175 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 ... 191 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 ... 207 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 ... 223 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 ... 239 */ sl@0: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 240 ... 255 */ sl@0: }; sl@0: sl@0: Tcl_DStringInit(&lineString); sl@0: Tcl_Gets(chan, &lineString); sl@0: line = Tcl_DStringValue(&lineString); sl@0: sl@0: fallback = (int) strtol(line, &line, 16); sl@0: symbol = (int) strtol(line, &line, 10); sl@0: numPages = (int) strtol(line, &line, 10); sl@0: Tcl_DStringFree(&lineString); sl@0: sl@0: if (numPages < 0) { sl@0: numPages = 0; sl@0: } else if (numPages > 256) { sl@0: numPages = 256; sl@0: } sl@0: sl@0: memset(used, 0, sizeof(used)); sl@0: sl@0: #undef PAGESIZE sl@0: #define PAGESIZE (256 * sizeof(unsigned short)) sl@0: sl@0: dataPtr = (TableEncodingData *) ckalloc(sizeof(TableEncodingData)); sl@0: memset(dataPtr, 0, sizeof(TableEncodingData)); sl@0: sl@0: dataPtr->fallback = fallback; sl@0: sl@0: /* sl@0: * Read the table that maps characters to Unicode. Performs a single sl@0: * malloc to get the memory for the array and all the pages needed by sl@0: * the array. sl@0: */ sl@0: sl@0: size = 256 * sizeof(unsigned short *) + numPages * PAGESIZE; sl@0: dataPtr->toUnicode = (unsigned short **) ckalloc(size); sl@0: memset(dataPtr->toUnicode, 0, size); sl@0: pageMemPtr = (unsigned short *) (dataPtr->toUnicode + 256); sl@0: sl@0: if (interp == NULL) { sl@0: objPtr = Tcl_NewObj(); sl@0: } else { sl@0: objPtr = Tcl_GetObjResult(interp); sl@0: } sl@0: for (i = 0; i < numPages; i++) { sl@0: int ch; sl@0: char *p; sl@0: sl@0: Tcl_ReadChars(chan, objPtr, 3 + 16 * (16 * 4 + 1), 0); sl@0: p = Tcl_GetString(objPtr); sl@0: hi = (staticHex[(unsigned int)p[0]] << 4) + staticHex[(unsigned int)p[1]]; sl@0: dataPtr->toUnicode[hi] = pageMemPtr; sl@0: p += 2; sl@0: for (lo = 0; lo < 256; lo++) { sl@0: if ((lo & 0x0f) == 0) { sl@0: p++; sl@0: } sl@0: ch = (staticHex[(unsigned int)p[0]] << 12) + (staticHex[(unsigned int)p[1]] << 8) sl@0: + (staticHex[(unsigned int)p[2]] << 4) + staticHex[(unsigned int)p[3]]; sl@0: if (ch != 0) { sl@0: used[ch >> 8] = 1; sl@0: } sl@0: *pageMemPtr = (unsigned short) ch; sl@0: pageMemPtr++; sl@0: p += 4; sl@0: } sl@0: } sl@0: if (interp == NULL) { sl@0: Tcl_DecrRefCount(objPtr); sl@0: } else { sl@0: Tcl_ResetResult(interp); sl@0: } sl@0: sl@0: if (type == ENCODING_DOUBLEBYTE) { sl@0: memset(dataPtr->prefixBytes, 1, sizeof(dataPtr->prefixBytes)); sl@0: } else { sl@0: for (hi = 1; hi < 256; hi++) { sl@0: if (dataPtr->toUnicode[hi] != NULL) { sl@0: dataPtr->prefixBytes[hi] = 1; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /* sl@0: * Invert toUnicode array to produce the fromUnicode array. Performs a sl@0: * single malloc to get the memory for the array and all the pages sl@0: * needed by the array. While reading in the toUnicode array, we sl@0: * remembered what pages that would be needed for the fromUnicode array. sl@0: */ sl@0: sl@0: if (symbol) { sl@0: used[0] = 1; sl@0: } sl@0: numPages = 0; sl@0: for (hi = 0; hi < 256; hi++) { sl@0: if (used[hi]) { sl@0: numPages++; sl@0: } sl@0: } sl@0: size = 256 * sizeof(unsigned short *) + numPages * PAGESIZE; sl@0: dataPtr->fromUnicode = (unsigned short **) ckalloc(size); sl@0: memset(dataPtr->fromUnicode, 0, size); sl@0: pageMemPtr = (unsigned short *) (dataPtr->fromUnicode + 256); sl@0: sl@0: for (hi = 0; hi < 256; hi++) { sl@0: if (dataPtr->toUnicode[hi] == NULL) { sl@0: dataPtr->toUnicode[hi] = emptyPage; sl@0: } else { sl@0: for (lo = 0; lo < 256; lo++) { sl@0: int ch; sl@0: sl@0: ch = dataPtr->toUnicode[hi][lo]; sl@0: if (ch != 0) { sl@0: unsigned short *page; sl@0: sl@0: page = dataPtr->fromUnicode[ch >> 8]; sl@0: if (page == NULL) { sl@0: page = pageMemPtr; sl@0: pageMemPtr += 256; sl@0: dataPtr->fromUnicode[ch >> 8] = page; sl@0: } sl@0: page[ch & 0xff] = (unsigned short) ((hi << 8) + lo); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: if (type == ENCODING_MULTIBYTE) { sl@0: /* sl@0: * If multibyte encodings don't have a backslash character, define sl@0: * one. Otherwise, on Windows, native file names won't work because sl@0: * the backslash in the file name will map to the unknown character sl@0: * (question mark) when converting from UTF-8 to external encoding. sl@0: */ sl@0: sl@0: if (dataPtr->fromUnicode[0] != NULL) { sl@0: if (dataPtr->fromUnicode[0]['\\'] == '\0') { sl@0: dataPtr->fromUnicode[0]['\\'] = '\\'; sl@0: } sl@0: } sl@0: } sl@0: if (symbol) { sl@0: unsigned short *page; sl@0: sl@0: /* sl@0: * Make a special symbol encoding that not only maps the symbol sl@0: * characters from their Unicode code points down into page 0, but sl@0: * also ensure that the characters on page 0 map to themselves. sl@0: * This is so that a symbol font can be used to display a simple sl@0: * string like "abcd" and have alpha, beta, chi, delta show up, sl@0: * rather than have "unknown" chars show up because strictly sl@0: * speaking the symbol font doesn't have glyphs for those low ascii sl@0: * chars. sl@0: */ sl@0: sl@0: page = dataPtr->fromUnicode[0]; sl@0: if (page == NULL) { sl@0: page = pageMemPtr; sl@0: dataPtr->fromUnicode[0] = page; sl@0: } sl@0: for (lo = 0; lo < 256; lo++) { sl@0: if (dataPtr->toUnicode[0][lo] != 0) { sl@0: page[lo] = (unsigned short) lo; sl@0: } sl@0: } sl@0: } sl@0: for (hi = 0; hi < 256; hi++) { sl@0: if (dataPtr->fromUnicode[hi] == NULL) { sl@0: dataPtr->fromUnicode[hi] = emptyPage; sl@0: } sl@0: } sl@0: /* sl@0: * For trailing 'R'everse encoding, see [Patch #689341] sl@0: */ sl@0: Tcl_DStringInit(&lineString); sl@0: do { sl@0: int len; sl@0: /* skip leading empty lines */ sl@0: while ((len = Tcl_Gets(chan, &lineString)) == 0) sl@0: ; sl@0: if (len < 0) { sl@0: break; sl@0: } sl@0: line = Tcl_DStringValue(&lineString); sl@0: if (line[0] != 'R') { sl@0: break; sl@0: } sl@0: for (Tcl_DStringSetLength(&lineString, 0); sl@0: (len = Tcl_Gets(chan, &lineString)) >= 0; sl@0: Tcl_DStringSetLength(&lineString, 0)) { sl@0: unsigned char* p; sl@0: int to, from; sl@0: if (len < 5) { sl@0: continue; sl@0: } sl@0: p = (unsigned char*) Tcl_DStringValue(&lineString); sl@0: to = (staticHex[p[0]] << 12) + (staticHex[p[1]] << 8) sl@0: + (staticHex[p[2]] << 4) + staticHex[p[3]]; sl@0: if (to == 0) { sl@0: continue; sl@0: } sl@0: for (p += 5, len -= 5; len >= 0 && *p; p += 5, len -= 5) { sl@0: from = (staticHex[p[0]] << 12) + (staticHex[p[1]] << 8) sl@0: + (staticHex[p[2]] << 4) + staticHex[p[3]]; sl@0: if (from == 0) { sl@0: continue; sl@0: } sl@0: dataPtr->fromUnicode[from >> 8][from & 0xff] = to; sl@0: } sl@0: } sl@0: } while (0); sl@0: Tcl_DStringFree(&lineString); sl@0: sl@0: encType.encodingName = name; sl@0: encType.toUtfProc = TableToUtfProc; sl@0: encType.fromUtfProc = TableFromUtfProc; sl@0: encType.freeProc = TableFreeProc; sl@0: encType.nullSize = (type == ENCODING_DOUBLEBYTE) ? 2 : 1; sl@0: encType.clientData = (ClientData) dataPtr; sl@0: return Tcl_CreateEncoding(&encType); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * LoadEscapeEncoding -- sl@0: * sl@0: * Helper function for LoadEncodingTable(). Loads a state machine sl@0: * that converts between Unicode and some other encoding. sl@0: * sl@0: * File contains text data that describes the escape sequences that sl@0: * are used to choose an encoding and the associated names for the sl@0: * sub-encodings. sl@0: * sl@0: * Results: sl@0: * The return value is the new encoding, or NULL if the encoding sl@0: * could not be created (because the file contained invalid data). sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static Tcl_Encoding sl@0: LoadEscapeEncoding(name, chan) sl@0: CONST char *name; /* Name for new encoding. */ sl@0: Tcl_Channel chan; /* File containing new encoding. */ sl@0: { sl@0: int i, missingSubEncoding = 0; sl@0: unsigned int size; sl@0: Tcl_DString escapeData; sl@0: char init[16], final[16]; sl@0: EscapeEncodingData *dataPtr; sl@0: Tcl_EncodingType type; sl@0: sl@0: init[0] = '\0'; sl@0: final[0] = '\0'; sl@0: Tcl_DStringInit(&escapeData); sl@0: sl@0: while (1) { sl@0: int argc; sl@0: CONST char **argv; sl@0: char *line; sl@0: Tcl_DString lineString; sl@0: sl@0: Tcl_DStringInit(&lineString); sl@0: if (Tcl_Gets(chan, &lineString) < 0) { sl@0: break; sl@0: } sl@0: line = Tcl_DStringValue(&lineString); sl@0: if (Tcl_SplitList(NULL, line, &argc, &argv) != TCL_OK) { sl@0: continue; sl@0: } sl@0: if (argc >= 2) { sl@0: if (strcmp(argv[0], "name") == 0) { sl@0: ; sl@0: } else if (strcmp(argv[0], "init") == 0) { sl@0: strncpy(init, argv[1], sizeof(init)); sl@0: init[sizeof(init) - 1] = '\0'; sl@0: } else if (strcmp(argv[0], "final") == 0) { sl@0: strncpy(final, argv[1], sizeof(final)); sl@0: final[sizeof(final) - 1] = '\0'; sl@0: } else { sl@0: EscapeSubTable est; sl@0: sl@0: strncpy(est.sequence, argv[1], sizeof(est.sequence)); sl@0: est.sequence[sizeof(est.sequence) - 1] = '\0'; sl@0: est.sequenceLen = strlen(est.sequence); sl@0: sl@0: strncpy(est.name, argv[0], sizeof(est.name)); sl@0: est.name[sizeof(est.name) - 1] = '\0'; sl@0: sl@0: /* sl@0: * Load the subencodings first so we're never stuck sl@0: * trying to use a half-loaded system encoding to sl@0: * open/read a *.enc file. sl@0: */ sl@0: sl@0: est.encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, est.name); sl@0: if ((est.encodingPtr == NULL) sl@0: || (est.encodingPtr->toUtfProc != TableToUtfProc)) { sl@0: missingSubEncoding = 1; sl@0: } sl@0: Tcl_DStringAppend(&escapeData, (char *) &est, sizeof(est)); sl@0: } sl@0: } sl@0: ckfree((char *) argv); sl@0: Tcl_DStringFree(&lineString); sl@0: } sl@0: if (missingSubEncoding) { sl@0: Tcl_DStringFree(&escapeData); sl@0: return NULL; sl@0: } sl@0: sl@0: size = sizeof(EscapeEncodingData) sl@0: - sizeof(EscapeSubTable) + Tcl_DStringLength(&escapeData); sl@0: dataPtr = (EscapeEncodingData *) ckalloc(size); sl@0: dataPtr->initLen = strlen(init); sl@0: strcpy(dataPtr->init, init); sl@0: dataPtr->finalLen = strlen(final); sl@0: strcpy(dataPtr->final, final); sl@0: dataPtr->numSubTables = Tcl_DStringLength(&escapeData) / sizeof(EscapeSubTable); sl@0: memcpy((VOID *) dataPtr->subTables, (VOID *) Tcl_DStringValue(&escapeData), sl@0: (size_t) Tcl_DStringLength(&escapeData)); sl@0: Tcl_DStringFree(&escapeData); sl@0: sl@0: memset(dataPtr->prefixBytes, 0, sizeof(dataPtr->prefixBytes)); sl@0: for (i = 0; i < dataPtr->numSubTables; i++) { sl@0: dataPtr->prefixBytes[UCHAR(dataPtr->subTables[i].sequence[0])] = 1; sl@0: } sl@0: if (dataPtr->init[0] != '\0') { sl@0: dataPtr->prefixBytes[UCHAR(dataPtr->init[0])] = 1; sl@0: } sl@0: if (dataPtr->final[0] != '\0') { sl@0: dataPtr->prefixBytes[UCHAR(dataPtr->final[0])] = 1; sl@0: } sl@0: sl@0: type.encodingName = name; sl@0: type.toUtfProc = EscapeToUtfProc; sl@0: type.fromUtfProc = EscapeFromUtfProc; sl@0: type.freeProc = EscapeFreeProc; sl@0: type.nullSize = 1; sl@0: type.clientData = (ClientData) dataPtr; sl@0: sl@0: return Tcl_CreateEncoding(&type); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * BinaryProc -- sl@0: * sl@0: * The default conversion when no other conversion is specified. sl@0: * No translation is done; source bytes are copied directly to sl@0: * destination bytes. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: BinaryProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* Not used. */ sl@0: CONST char *src; /* Source string (unknown encoding). */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: int result; sl@0: sl@0: result = TCL_OK; sl@0: dstLen -= TCL_UTF_MAX - 1; sl@0: if (dstLen < 0) { sl@0: dstLen = 0; sl@0: } sl@0: if (srcLen > dstLen) { sl@0: srcLen = dstLen; sl@0: result = TCL_CONVERT_NOSPACE; sl@0: } sl@0: sl@0: *srcReadPtr = srcLen; sl@0: *dstWrotePtr = srcLen; sl@0: *dstCharsPtr = srcLen; sl@0: memcpy((void *) dst, (void *) src, (size_t) srcLen); sl@0: return result; sl@0: } sl@0: sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * UtfExtToUtfIntProc -- sl@0: * sl@0: * Convert from UTF-8 to UTF-8. While converting null-bytes from sl@0: * the Tcl's internal representation (0xc0, 0x80) to the official sl@0: * representation (0x00). See UtfToUtfProc for details. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: static int sl@0: UtfIntToUtfExtProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* Not used. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: return UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr, 1); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * UtfExtToUtfIntProc -- sl@0: * sl@0: * Convert from UTF-8 to UTF-8 while converting null-bytes from sl@0: * the official representation (0x00) to Tcl's internal sl@0: * representation (0xc0, 0x80). See UtfToUtfProc for details. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: static int sl@0: UtfExtToUtfIntProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* Not used. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: return UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr, 0); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * UtfToUtfProc -- sl@0: * sl@0: * Convert from UTF-8 to UTF-8. Note that the UTF-8 to UTF-8 sl@0: * translation is not a no-op, because it will turn a stream of sl@0: * improperly formed UTF-8 into a properly formed stream. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: UtfToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr, pureNullMode) sl@0: ClientData clientData; /* Not used. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: int pureNullMode; /* Convert embedded nulls from sl@0: * internal representation to real sl@0: * null-bytes or vice versa */ sl@0: sl@0: { sl@0: CONST char *srcStart, *srcEnd, *srcClose; sl@0: char *dstStart, *dstEnd; sl@0: int result, numChars; sl@0: Tcl_UniChar ch; sl@0: sl@0: result = TCL_OK; sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: srcClose = srcEnd; sl@0: if ((flags & TCL_ENCODING_END) == 0) { sl@0: srcClose -= TCL_UTF_MAX; sl@0: } sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - TCL_UTF_MAX; sl@0: sl@0: for (numChars = 0; src < srcEnd; numChars++) { sl@0: if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { sl@0: /* sl@0: * If there is more string to follow, this will ensure that the sl@0: * last UTF-8 character in the source buffer hasn't been cut off. sl@0: */ sl@0: sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: break; sl@0: } sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: if (UCHAR(*src) < 0x80 && sl@0: !(UCHAR(*src) == 0 && pureNullMode == 0)) { sl@0: /* sl@0: * Copy 7bit chatacters, but skip null-bytes when we are sl@0: * in input mode, so that they get converted to 0xc080. sl@0: */ sl@0: *dst++ = *src++; sl@0: } else if (pureNullMode == 1 && sl@0: UCHAR(*src) == 0xc0 && sl@0: UCHAR(*(src+1)) == 0x80) { sl@0: /* sl@0: * Convert 0xc080 to real nulls when we are in output mode. sl@0: */ sl@0: *dst++ = 0; sl@0: src += 2; sl@0: } else if (!Tcl_UtfCharComplete(src, srcEnd - src)) { sl@0: /* Always check before using Tcl_UtfToUniChar. Not doing sl@0: * can so cause it run beyond the endof the buffer! If we sl@0: * * happen such an incomplete char its byts are made to * sl@0: * represent themselves. sl@0: */ sl@0: sl@0: ch = (Tcl_UniChar) *src; sl@0: src += 1; sl@0: dst += Tcl_UniCharToUtf(ch, dst); sl@0: } else { sl@0: src += Tcl_UtfToUniChar(src, &ch); sl@0: dst += Tcl_UniCharToUtf(ch, dst); sl@0: } sl@0: } sl@0: sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * UnicodeToUtfProc -- sl@0: * sl@0: * Convert from Unicode to UTF-8. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: UnicodeToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* Not used. */ sl@0: CONST char *src; /* Source string in Unicode. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: CONST char *srcStart, *srcEnd; sl@0: char *dstEnd, *dstStart; sl@0: int result, numChars; sl@0: Tcl_UniChar ch; sl@0: sl@0: result = TCL_OK; sl@0: if ((srcLen % sizeof(Tcl_UniChar)) != 0) { sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: srcLen /= sizeof(Tcl_UniChar); sl@0: srcLen *= sizeof(Tcl_UniChar); sl@0: } sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - TCL_UTF_MAX; sl@0: sl@0: for (numChars = 0; src < srcEnd; numChars++) { sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: /* sl@0: * Special case for 1-byte utf chars for speed. Make sure we sl@0: * work with Tcl_UniChar-size data. sl@0: */ sl@0: ch = *(Tcl_UniChar *)src; sl@0: if (ch && ch < 0x80) { sl@0: *dst++ = (ch & 0xFF); sl@0: } else { sl@0: dst += Tcl_UniCharToUtf(ch, dst); sl@0: } sl@0: src += sizeof(Tcl_UniChar); sl@0: } sl@0: sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * UtfToUnicodeProc -- sl@0: * sl@0: * Convert from UTF-8 to Unicode. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: UtfToUnicodeProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* TableEncodingData that specifies encoding. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: CONST char *srcStart, *srcEnd, *srcClose, *dstStart, *dstEnd; sl@0: int result, numChars; sl@0: Tcl_UniChar ch; sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: srcClose = srcEnd; sl@0: if ((flags & TCL_ENCODING_END) == 0) { sl@0: srcClose -= TCL_UTF_MAX; sl@0: } sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - sizeof(Tcl_UniChar); sl@0: sl@0: result = TCL_OK; sl@0: for (numChars = 0; src < srcEnd; numChars++) { sl@0: if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { sl@0: /* sl@0: * If there is more string to follow, this will ensure that the sl@0: * last UTF-8 character in the source buffer hasn't been cut off. sl@0: */ sl@0: sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: break; sl@0: } sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: src += TclUtfToUniChar(src, &ch); sl@0: /* sl@0: * Need to handle this in a way that won't cause misalignment sl@0: * by casting dst to a Tcl_UniChar. [Bug 1122671] sl@0: * XXX: This hard-codes the assumed size of Tcl_UniChar as 2. sl@0: */ sl@0: #ifdef WORDS_BIGENDIAN sl@0: *dst++ = (ch >> 8); sl@0: *dst++ = (ch & 0xFF); sl@0: #else sl@0: *dst++ = (ch & 0xFF); sl@0: *dst++ = (ch >> 8); sl@0: #endif sl@0: } sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * TableToUtfProc -- sl@0: * sl@0: * Convert from the encoding specified by the TableEncodingData into sl@0: * UTF-8. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: TableToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* TableEncodingData that specifies sl@0: * encoding. */ sl@0: CONST char *src; /* Source string in specified encoding. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: CONST char *srcStart, *srcEnd; sl@0: char *dstEnd, *dstStart, *prefixBytes; sl@0: int result, byte, numChars; sl@0: Tcl_UniChar ch; sl@0: unsigned short **toUnicode; sl@0: unsigned short *pageZero; sl@0: TableEncodingData *dataPtr; sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - TCL_UTF_MAX; sl@0: sl@0: dataPtr = (TableEncodingData *) clientData; sl@0: toUnicode = dataPtr->toUnicode; sl@0: prefixBytes = dataPtr->prefixBytes; sl@0: pageZero = toUnicode[0]; sl@0: sl@0: result = TCL_OK; sl@0: for (numChars = 0; src < srcEnd; numChars++) { sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: byte = *((unsigned char *) src); sl@0: if (prefixBytes[byte]) { sl@0: src++; sl@0: if (src >= srcEnd) { sl@0: src--; sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: break; sl@0: } sl@0: ch = toUnicode[byte][*((unsigned char *) src)]; sl@0: } else { sl@0: ch = pageZero[byte]; sl@0: } sl@0: if ((ch == 0) && (byte != 0)) { sl@0: if (flags & TCL_ENCODING_STOPONERROR) { sl@0: result = TCL_CONVERT_SYNTAX; sl@0: break; sl@0: } sl@0: if (prefixBytes[byte]) { sl@0: src--; sl@0: } sl@0: ch = (Tcl_UniChar) byte; sl@0: } sl@0: /* sl@0: * Special case for 1-byte utf chars for speed. sl@0: */ sl@0: if (ch && ch < 0x80) { sl@0: *dst++ = (char) ch; sl@0: } else { sl@0: dst += Tcl_UniCharToUtf(ch, dst); sl@0: } sl@0: src++; sl@0: } sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * TableFromUtfProc -- sl@0: * sl@0: * Convert from UTF-8 into the encoding specified by the sl@0: * TableEncodingData. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: TableFromUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* TableEncodingData that specifies sl@0: * encoding. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: CONST char *srcStart, *srcEnd, *srcClose; sl@0: char *dstStart, *dstEnd, *prefixBytes; sl@0: Tcl_UniChar ch; sl@0: int result, len, word, numChars; sl@0: TableEncodingData *dataPtr; sl@0: unsigned short **fromUnicode; sl@0: sl@0: result = TCL_OK; sl@0: sl@0: dataPtr = (TableEncodingData *) clientData; sl@0: prefixBytes = dataPtr->prefixBytes; sl@0: fromUnicode = dataPtr->fromUnicode; sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: srcClose = srcEnd; sl@0: if ((flags & TCL_ENCODING_END) == 0) { sl@0: srcClose -= TCL_UTF_MAX; sl@0: } sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - 1; sl@0: sl@0: for (numChars = 0; src < srcEnd; numChars++) { sl@0: if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { sl@0: /* sl@0: * If there is more string to follow, this will ensure that the sl@0: * last UTF-8 character in the source buffer hasn't been cut off. sl@0: */ sl@0: sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: break; sl@0: } sl@0: len = TclUtfToUniChar(src, &ch); sl@0: sl@0: #if TCL_UTF_MAX > 3 sl@0: /* sl@0: * This prevents a crash condition. More evaluation is required sl@0: * for full support of int Tcl_UniChar. [Bug 1004065] sl@0: */ sl@0: if (ch & 0xffff0000) { sl@0: word = 0; sl@0: } else sl@0: #endif sl@0: word = fromUnicode[(ch >> 8)][ch & 0xff]; sl@0: sl@0: if ((word == 0) && (ch != 0)) { sl@0: if (flags & TCL_ENCODING_STOPONERROR) { sl@0: result = TCL_CONVERT_UNKNOWN; sl@0: break; sl@0: } sl@0: word = dataPtr->fallback; sl@0: } sl@0: if (prefixBytes[(word >> 8)] != 0) { sl@0: if (dst + 1 > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: dst[0] = (char) (word >> 8); sl@0: dst[1] = (char) word; sl@0: dst += 2; sl@0: } else { sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: dst[0] = (char) word; sl@0: dst++; sl@0: } sl@0: src += len; sl@0: } sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * TableFreeProc -- sl@0: * sl@0: * This procedure is invoked when an encoding is deleted. It deletes sl@0: * the memory used by the TableEncodingData. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * Memory freed. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static void sl@0: TableFreeProc(clientData) sl@0: ClientData clientData; /* TableEncodingData that specifies sl@0: * encoding. */ sl@0: { sl@0: TableEncodingData *dataPtr; sl@0: sl@0: /* sl@0: * Make sure we aren't freeing twice on shutdown. [Bug #219314] sl@0: */ sl@0: sl@0: dataPtr = (TableEncodingData *) clientData; sl@0: ckfree((char *) dataPtr->toUnicode); sl@0: ckfree((char *) dataPtr->fromUnicode); sl@0: ckfree((char *) dataPtr); sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * EscapeToUtfProc -- sl@0: * sl@0: * Convert from the encoding specified by the EscapeEncodingData into sl@0: * UTF-8. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: EscapeToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* EscapeEncodingData that specifies sl@0: * encoding. */ sl@0: CONST char *src; /* Source string in specified encoding. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: EscapeEncodingData *dataPtr; sl@0: char *prefixBytes, *tablePrefixBytes; sl@0: unsigned short **tableToUnicode; sl@0: Encoding *encodingPtr; sl@0: int state, result, numChars; sl@0: CONST char *srcStart, *srcEnd; sl@0: char *dstStart, *dstEnd; sl@0: sl@0: result = TCL_OK; sl@0: sl@0: tablePrefixBytes = NULL; /* lint. */ sl@0: tableToUnicode = NULL; /* lint. */ sl@0: sl@0: dataPtr = (EscapeEncodingData *) clientData; sl@0: prefixBytes = dataPtr->prefixBytes; sl@0: encodingPtr = NULL; sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - TCL_UTF_MAX; sl@0: sl@0: state = (int) *statePtr; sl@0: if (flags & TCL_ENCODING_START) { sl@0: state = 0; sl@0: } sl@0: sl@0: for (numChars = 0; src < srcEnd; ) { sl@0: int byte, hi, lo, ch; sl@0: sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: byte = *((unsigned char *) src); sl@0: if (prefixBytes[byte]) { sl@0: unsigned int left, len, longest; sl@0: int checked, i; sl@0: EscapeSubTable *subTablePtr; sl@0: sl@0: /* sl@0: * Saw the beginning of an escape sequence. sl@0: */ sl@0: sl@0: left = srcEnd - src; sl@0: len = dataPtr->initLen; sl@0: longest = len; sl@0: checked = 0; sl@0: if (len <= left) { sl@0: checked++; sl@0: if ((len > 0) && sl@0: (memcmp(src, dataPtr->init, len) == 0)) { sl@0: /* sl@0: * If we see initialization string, skip it, even if we're sl@0: * not at the beginning of the buffer. sl@0: */ sl@0: sl@0: src += len; sl@0: continue; sl@0: } sl@0: } sl@0: len = dataPtr->finalLen; sl@0: if (len > longest) { sl@0: longest = len; sl@0: } sl@0: if (len <= left) { sl@0: checked++; sl@0: if ((len > 0) && sl@0: (memcmp(src, dataPtr->final, len) == 0)) { sl@0: /* sl@0: * If we see finalization string, skip it, even if we're sl@0: * not at the end of the buffer. sl@0: */ sl@0: sl@0: src += len; sl@0: continue; sl@0: } sl@0: } sl@0: subTablePtr = dataPtr->subTables; sl@0: for (i = 0; i < dataPtr->numSubTables; i++) { sl@0: len = subTablePtr->sequenceLen; sl@0: if (len > longest) { sl@0: longest = len; sl@0: } sl@0: if (len <= left) { sl@0: checked++; sl@0: if ((len > 0) && sl@0: (memcmp(src, subTablePtr->sequence, len) == 0)) { sl@0: state = i; sl@0: encodingPtr = NULL; sl@0: subTablePtr = NULL; sl@0: src += len; sl@0: break; sl@0: } sl@0: } sl@0: subTablePtr++; sl@0: } sl@0: if (subTablePtr == NULL) { sl@0: /* sl@0: * A match was found, the escape sequence was consumed, and sl@0: * the state was updated. sl@0: */ sl@0: sl@0: continue; sl@0: } sl@0: sl@0: /* sl@0: * We have a split-up or unrecognized escape sequence. If we sl@0: * checked all the sequences, then it's a syntax error, sl@0: * otherwise we need more bytes to determine a match. sl@0: */ sl@0: sl@0: if ((checked == dataPtr->numSubTables + 2) sl@0: || (flags & TCL_ENCODING_END)) { sl@0: if ((flags & TCL_ENCODING_STOPONERROR) == 0) { sl@0: /* sl@0: * Skip the unknown escape sequence. sl@0: */ sl@0: sl@0: src += longest; sl@0: continue; sl@0: } sl@0: result = TCL_CONVERT_SYNTAX; sl@0: } else { sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: } sl@0: break; sl@0: } sl@0: sl@0: if (encodingPtr == NULL) { sl@0: TableEncodingData *tableDataPtr; sl@0: sl@0: encodingPtr = GetTableEncoding(dataPtr, state); sl@0: tableDataPtr = (TableEncodingData *) encodingPtr->clientData; sl@0: tablePrefixBytes = tableDataPtr->prefixBytes; sl@0: tableToUnicode = tableDataPtr->toUnicode; sl@0: } sl@0: if (tablePrefixBytes[byte]) { sl@0: src++; sl@0: if (src >= srcEnd) { sl@0: src--; sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: break; sl@0: } sl@0: hi = byte; sl@0: lo = *((unsigned char *) src); sl@0: } else { sl@0: hi = 0; sl@0: lo = byte; sl@0: } sl@0: ch = tableToUnicode[hi][lo]; sl@0: dst += Tcl_UniCharToUtf(ch, dst); sl@0: src++; sl@0: numChars++; sl@0: } sl@0: sl@0: *statePtr = (Tcl_EncodingState) state; sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * EscapeFromUtfProc -- sl@0: * sl@0: * Convert from UTF-8 into the encoding specified by the sl@0: * EscapeEncodingData. sl@0: * sl@0: * Results: sl@0: * Returns TCL_OK if conversion was successful. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: EscapeFromUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen, sl@0: srcReadPtr, dstWrotePtr, dstCharsPtr) sl@0: ClientData clientData; /* EscapeEncodingData that specifies sl@0: * encoding. */ sl@0: CONST char *src; /* Source string in UTF-8. */ sl@0: int srcLen; /* Source string length in bytes. */ sl@0: int flags; /* Conversion control flags. */ sl@0: Tcl_EncodingState *statePtr;/* Place for conversion routine to store sl@0: * state information used during a piecewise sl@0: * conversion. Contents of statePtr are sl@0: * initialized and/or reset by conversion sl@0: * routine under control of flags argument. */ sl@0: char *dst; /* Output buffer in which converted string sl@0: * is stored. */ sl@0: int dstLen; /* The maximum length of output buffer in sl@0: * bytes. */ sl@0: int *srcReadPtr; /* Filled with the number of bytes from the sl@0: * source string that were converted. This sl@0: * may be less than the original source length sl@0: * if there was a problem converting some sl@0: * source characters. */ sl@0: int *dstWrotePtr; /* Filled with the number of bytes that were sl@0: * stored in the output buffer as a result of sl@0: * the conversion. */ sl@0: int *dstCharsPtr; /* Filled with the number of characters that sl@0: * correspond to the bytes stored in the sl@0: * output buffer. */ sl@0: { sl@0: EscapeEncodingData *dataPtr; sl@0: Encoding *encodingPtr; sl@0: CONST char *srcStart, *srcEnd, *srcClose; sl@0: char *dstStart, *dstEnd; sl@0: int state, result, numChars; sl@0: TableEncodingData *tableDataPtr; sl@0: char *tablePrefixBytes; sl@0: unsigned short **tableFromUnicode; sl@0: sl@0: result = TCL_OK; sl@0: sl@0: dataPtr = (EscapeEncodingData *) clientData; sl@0: sl@0: srcStart = src; sl@0: srcEnd = src + srcLen; sl@0: srcClose = srcEnd; sl@0: if ((flags & TCL_ENCODING_END) == 0) { sl@0: srcClose -= TCL_UTF_MAX; sl@0: } sl@0: sl@0: dstStart = dst; sl@0: dstEnd = dst + dstLen - 1; sl@0: sl@0: /* sl@0: * RFC1468 states that the text starts in ASCII, and switches to Japanese sl@0: * characters, and that the text must end in ASCII. [Patch #474358] sl@0: */ sl@0: sl@0: if (flags & TCL_ENCODING_START) { sl@0: state = 0; sl@0: if ((dst + dataPtr->initLen) > dstEnd) { sl@0: *srcReadPtr = 0; sl@0: *dstWrotePtr = 0; sl@0: return TCL_CONVERT_NOSPACE; sl@0: } sl@0: memcpy((VOID *) dst, (VOID *) dataPtr->init, sl@0: (size_t) dataPtr->initLen); sl@0: dst += dataPtr->initLen; sl@0: } else { sl@0: state = (int) *statePtr; sl@0: } sl@0: sl@0: encodingPtr = GetTableEncoding(dataPtr, state); sl@0: tableDataPtr = (TableEncodingData *) encodingPtr->clientData; sl@0: tablePrefixBytes = tableDataPtr->prefixBytes; sl@0: tableFromUnicode = tableDataPtr->fromUnicode; sl@0: sl@0: for (numChars = 0; src < srcEnd; numChars++) { sl@0: unsigned int len; sl@0: int word; sl@0: Tcl_UniChar ch; sl@0: sl@0: if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) { sl@0: /* sl@0: * If there is more string to follow, this will ensure that the sl@0: * last UTF-8 character in the source buffer hasn't been cut off. sl@0: */ sl@0: sl@0: result = TCL_CONVERT_MULTIBYTE; sl@0: break; sl@0: } sl@0: len = TclUtfToUniChar(src, &ch); sl@0: word = tableFromUnicode[(ch >> 8)][ch & 0xff]; sl@0: sl@0: if ((word == 0) && (ch != 0)) { sl@0: int oldState; sl@0: EscapeSubTable *subTablePtr; sl@0: sl@0: oldState = state; sl@0: for (state = 0; state < dataPtr->numSubTables; state++) { sl@0: encodingPtr = GetTableEncoding(dataPtr, state); sl@0: tableDataPtr = (TableEncodingData *) encodingPtr->clientData; sl@0: word = tableDataPtr->fromUnicode[(ch >> 8)][ch & 0xff]; sl@0: if (word != 0) { sl@0: break; sl@0: } sl@0: } sl@0: sl@0: if (word == 0) { sl@0: state = oldState; sl@0: if (flags & TCL_ENCODING_STOPONERROR) { sl@0: result = TCL_CONVERT_UNKNOWN; sl@0: break; sl@0: } sl@0: encodingPtr = GetTableEncoding(dataPtr, state); sl@0: tableDataPtr = (TableEncodingData *) encodingPtr->clientData; sl@0: word = tableDataPtr->fallback; sl@0: } sl@0: sl@0: tablePrefixBytes = tableDataPtr->prefixBytes; sl@0: tableFromUnicode = tableDataPtr->fromUnicode; sl@0: sl@0: /* sl@0: * The state variable has the value of oldState when word is 0. sl@0: * In this case, the escape sequense should not be copied to dst sl@0: * because the current character set is not changed. sl@0: */ sl@0: if (state != oldState) { sl@0: subTablePtr = &dataPtr->subTables[state]; sl@0: if ((dst + subTablePtr->sequenceLen) > dstEnd) { sl@0: /* sl@0: * If there is no space to write the escape sequence, the sl@0: * state variable must be changed to the value of oldState sl@0: * variable because this escape sequence must be written sl@0: * in the next conversion. sl@0: */ sl@0: state = oldState; sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: memcpy((VOID *) dst, (VOID *) subTablePtr->sequence, sl@0: (size_t) subTablePtr->sequenceLen); sl@0: dst += subTablePtr->sequenceLen; sl@0: } sl@0: } sl@0: sl@0: if (tablePrefixBytes[(word >> 8)] != 0) { sl@0: if (dst + 1 > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: dst[0] = (char) (word >> 8); sl@0: dst[1] = (char) word; sl@0: dst += 2; sl@0: } else { sl@0: if (dst > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: break; sl@0: } sl@0: dst[0] = (char) word; sl@0: dst++; sl@0: } sl@0: src += len; sl@0: } sl@0: sl@0: if ((result == TCL_OK) && (flags & TCL_ENCODING_END)) { sl@0: unsigned int len = dataPtr->subTables[0].sequenceLen; sl@0: /* sl@0: * [Bug 1516109]. sl@0: * Certain encodings like iso2022-jp need to write sl@0: * an escape sequence after all characters have sl@0: * been converted. This logic checks that enough sl@0: * room is available in the buffer for the escape bytes. sl@0: * The TCL_ENCODING_END flag is cleared after a final sl@0: * escape sequence has been added to the buffer so sl@0: * that another call to this method does not attempt sl@0: * to append escape bytes a second time. sl@0: */ sl@0: if ((dst + dataPtr->finalLen + (state?len:0)) > dstEnd) { sl@0: result = TCL_CONVERT_NOSPACE; sl@0: } else { sl@0: if (state) { sl@0: memcpy((VOID *) dst, (VOID *) dataPtr->subTables[0].sequence, sl@0: (size_t) len); sl@0: dst += len; sl@0: } sl@0: memcpy((VOID *) dst, (VOID *) dataPtr->final, sl@0: (size_t) dataPtr->finalLen); sl@0: dst += dataPtr->finalLen; sl@0: state &= ~TCL_ENCODING_END; sl@0: } sl@0: } sl@0: sl@0: *statePtr = (Tcl_EncodingState) state; sl@0: *srcReadPtr = src - srcStart; sl@0: *dstWrotePtr = dst - dstStart; sl@0: *dstCharsPtr = numChars; sl@0: return result; sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * EscapeFreeProc -- sl@0: * sl@0: * This procedure is invoked when an EscapeEncodingData encoding is sl@0: * deleted. It deletes the memory used by the encoding. sl@0: * sl@0: * Results: sl@0: * None. sl@0: * sl@0: * Side effects: sl@0: * Memory freed. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static void sl@0: EscapeFreeProc(clientData) sl@0: ClientData clientData; /* EscapeEncodingData that specifies encoding. */ sl@0: { sl@0: EscapeEncodingData *dataPtr; sl@0: EscapeSubTable *subTablePtr; sl@0: int i; sl@0: sl@0: dataPtr = (EscapeEncodingData *) clientData; sl@0: if (dataPtr == NULL) { sl@0: return; sl@0: } sl@0: subTablePtr = dataPtr->subTables; sl@0: for (i = 0; i < dataPtr->numSubTables; i++) { sl@0: FreeEncoding((Tcl_Encoding) subTablePtr->encodingPtr); sl@0: subTablePtr++; sl@0: } sl@0: ckfree((char *) dataPtr); sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * GetTableEncoding -- sl@0: * sl@0: * Helper function for the EscapeEncodingData conversions. Gets the sl@0: * encoding (of type TextEncodingData) that represents the specified sl@0: * state. sl@0: * sl@0: * Results: sl@0: * The return value is the encoding. sl@0: * sl@0: * Side effects: sl@0: * If the encoding that represents the specified state has not sl@0: * already been used by this EscapeEncoding, it will be loaded sl@0: * and cached in the dataPtr. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static Encoding * sl@0: GetTableEncoding(dataPtr, state) sl@0: EscapeEncodingData *dataPtr;/* Contains names of encodings. */ sl@0: int state; /* Index in dataPtr of desired Encoding. */ sl@0: { sl@0: EscapeSubTable *subTablePtr; sl@0: Encoding *encodingPtr; sl@0: sl@0: subTablePtr = &dataPtr->subTables[state]; sl@0: encodingPtr = subTablePtr->encodingPtr; sl@0: if (encodingPtr == NULL) { sl@0: /* sl@0: * Now that escape encodings load their sub-encodings first, and sl@0: * fail to load if any sub-encodings are missing, this branch should sl@0: * never happen. sl@0: */ sl@0: encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, subTablePtr->name); sl@0: if ((encodingPtr == NULL) sl@0: || (encodingPtr->toUtfProc != TableToUtfProc)) { sl@0: panic("EscapeToUtfProc: invalid sub table"); sl@0: } sl@0: subTablePtr->encodingPtr = encodingPtr; sl@0: } sl@0: return encodingPtr; sl@0: } sl@0: sl@0: /* sl@0: *--------------------------------------------------------------------------- sl@0: * sl@0: * unilen -- sl@0: * sl@0: * A helper function for the Tcl_ExternalToUtf functions. This sl@0: * function is similar to strlen for double-byte characters: it sl@0: * returns the number of bytes in a 0x0000 terminated string. sl@0: * sl@0: * Results: sl@0: * As above. sl@0: * sl@0: * Side effects: sl@0: * None. sl@0: * sl@0: *--------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static size_t sl@0: unilen(src) sl@0: CONST char *src; sl@0: { sl@0: unsigned short *p; sl@0: sl@0: p = (unsigned short *) src; sl@0: while (*p != 0x0000) { sl@0: p++; sl@0: } sl@0: return (char *) p - src; sl@0: } sl@0: sl@0: /* sl@0: *------------------------------------------------------------------------- sl@0: * sl@0: * TclFindEncodings -- sl@0: * sl@0: * Find and load the encoding file for this operating system. sl@0: * Before this is called, Tcl makes assumptions about the sl@0: * native string representation, but the true encoding is not sl@0: * assured. sl@0: * sl@0: * Results: sl@0: * Return result of TclpInitLibraryPath, which reports whether the sl@0: * path is clean (0) or dirty (1) UTF. sl@0: * sl@0: * Side effects: sl@0: * Varied, see the respective initialization routines. sl@0: * sl@0: *------------------------------------------------------------------------- sl@0: */ sl@0: sl@0: static int sl@0: TclFindEncodings(argv0) sl@0: CONST char *argv0; /* Name of executable from argv[0] to main() sl@0: * in native multi-byte encoding. */ sl@0: { sl@0: int mustCleanUtf = 0; sl@0: sl@0: if (encodingsInitialized == 0) { sl@0: /* sl@0: * Double check inside the mutex. There may be calls sl@0: * back into this routine from some of the procedures below. sl@0: */ sl@0: sl@0: TclpInitLock(); sl@0: if (encodingsInitialized == 0) { sl@0: char *native; sl@0: Tcl_Obj *pathPtr; sl@0: Tcl_DString libPath, buffer; sl@0: sl@0: /* sl@0: * Have to set this bit here to avoid deadlock with the sl@0: * routines below us that call into TclInitSubsystems. sl@0: */ sl@0: sl@0: encodingsInitialized = 1; sl@0: sl@0: native = TclpFindExecutable(argv0); sl@0: mustCleanUtf = TclpInitLibraryPath(native); sl@0: sl@0: /* sl@0: * The library path was set in the TclpInitLibraryPath routine. sl@0: * The string set is a dirty UTF string. To preserve the value sl@0: * convert the UTF string back to native before setting the new sl@0: * default encoding. sl@0: */ sl@0: sl@0: pathPtr = TclGetLibraryPath(); sl@0: if ((pathPtr != NULL) && mustCleanUtf) { sl@0: Tcl_UtfToExternalDString(NULL, Tcl_GetString(pathPtr), -1, sl@0: &libPath); sl@0: } sl@0: sl@0: TclpSetInitialEncodings(); sl@0: sl@0: /* sl@0: * Now convert the native string back to UTF. sl@0: */ sl@0: sl@0: if ((pathPtr != NULL) && mustCleanUtf) { sl@0: Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&libPath), -1, sl@0: &buffer); sl@0: pathPtr = Tcl_NewStringObj(Tcl_DStringValue(&buffer), -1); sl@0: TclSetLibraryPath(pathPtr); sl@0: sl@0: Tcl_DStringFree(&libPath); sl@0: Tcl_DStringFree(&buffer); sl@0: } sl@0: } sl@0: TclpInitUnlock(); sl@0: } sl@0: sl@0: return mustCleanUtf; sl@0: }