| /* |
| ** 2001 September 15 |
| ** |
| ** The author disclaims copyright to this source code. In place of |
| ** a legal notice, here is a blessing: |
| ** |
| ** May you do good and not evil. |
| ** May you find forgiveness for yourself and forgive others. |
| ** May you share freely, never taking more than you give. |
| ** |
| ************************************************************************* |
| ** Code for testing the utf.c module in SQLite. This code |
| ** is not included in the SQLite library. It is used for automated |
| ** testing of the SQLite library. Specifically, the code in this file |
| ** is used for testing the SQLite routines for converting between |
| ** the various supported unicode encodings. |
| */ |
| #include "sqliteInt.h" |
| #include "vdbeInt.h" |
| #if defined(INCLUDE_SQLITE_TCL_H) |
| # include "sqlite_tcl.h" |
| #else |
| # include "tcl.h" |
| #endif |
| #include <stdlib.h> |
| #include <string.h> |
| |
| /* |
| ** The first argument is a TCL UTF-8 string. Return the byte array |
| ** object with the encoded representation of the string, including |
| ** the NULL terminator. |
| */ |
| static int SQLITE_TCLAPI binarize( |
| void * clientData, |
| Tcl_Interp *interp, |
| int objc, |
| Tcl_Obj *CONST objv[] |
| ){ |
| int len; |
| char *bytes; |
| Tcl_Obj *pRet; |
| assert(objc==2); |
| |
| bytes = Tcl_GetStringFromObj(objv[1], &len); |
| pRet = Tcl_NewByteArrayObj((u8*)bytes, len+1); |
| Tcl_SetObjResult(interp, pRet); |
| return TCL_OK; |
| } |
| |
| /* |
| ** Usage: test_value_overhead <repeat-count> <do-calls>. |
| ** |
| ** This routine is used to test the overhead of calls to |
| ** sqlite3_value_text(), on a value that contains a UTF-8 string. The idea |
| ** is to figure out whether or not it is a problem to use sqlite3_value |
| ** structures with collation sequence functions. |
| ** |
| ** If <do-calls> is 0, then the calls to sqlite3_value_text() are not |
| ** actually made. |
| */ |
| static int SQLITE_TCLAPI test_value_overhead( |
| void * clientData, |
| Tcl_Interp *interp, |
| int objc, |
| Tcl_Obj *CONST objv[] |
| ){ |
| int do_calls; |
| int repeat_count; |
| int i; |
| Mem val; |
| |
| if( objc!=3 ){ |
| Tcl_AppendResult(interp, "wrong # args: should be \"", |
| Tcl_GetStringFromObj(objv[0], 0), " <repeat-count> <do-calls>", 0); |
| return TCL_ERROR; |
| } |
| |
| if( Tcl_GetIntFromObj(interp, objv[1], &repeat_count) ) return TCL_ERROR; |
| if( Tcl_GetIntFromObj(interp, objv[2], &do_calls) ) return TCL_ERROR; |
| |
| val.flags = MEM_Str|MEM_Term|MEM_Static; |
| val.z = "hello world"; |
| val.enc = SQLITE_UTF8; |
| |
| for(i=0; i<repeat_count; i++){ |
| if( do_calls ){ |
| sqlite3_value_text(&val); |
| } |
| } |
| |
| return TCL_OK; |
| } |
| |
| static u8 name_to_enc(Tcl_Interp *interp, Tcl_Obj *pObj){ |
| struct EncName { |
| char *zName; |
| u8 enc; |
| } encnames[] = { |
| { "UTF8", SQLITE_UTF8 }, |
| { "UTF16LE", SQLITE_UTF16LE }, |
| { "UTF16BE", SQLITE_UTF16BE }, |
| { "UTF16", SQLITE_UTF16 }, |
| { 0, 0 } |
| }; |
| struct EncName *pEnc; |
| char *z = Tcl_GetString(pObj); |
| for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ |
| if( 0==sqlite3StrICmp(z, pEnc->zName) ){ |
| break; |
| } |
| } |
| if( !pEnc->enc ){ |
| Tcl_AppendResult(interp, "No such encoding: ", z, 0); |
| } |
| if( pEnc->enc==SQLITE_UTF16 ){ |
| return SQLITE_UTF16NATIVE; |
| } |
| return pEnc->enc; |
| } |
| |
| /* |
| ** Usage: test_translate <string/blob> <from enc> <to enc> ?<transient>? |
| ** |
| */ |
| static int SQLITE_TCLAPI test_translate( |
| void * clientData, |
| Tcl_Interp *interp, |
| int objc, |
| Tcl_Obj *CONST objv[] |
| ){ |
| u8 enc_from; |
| u8 enc_to; |
| sqlite3_value *pVal; |
| |
| char *z; |
| int len; |
| void (*xDel)(void *p) = SQLITE_STATIC; |
| |
| if( objc!=4 && objc!=5 ){ |
| Tcl_AppendResult(interp, "wrong # args: should be \"", |
| Tcl_GetStringFromObj(objv[0], 0), |
| " <string/blob> <from enc> <to enc>", 0 |
| ); |
| return TCL_ERROR; |
| } |
| if( objc==5 ){ |
| xDel = sqlite3_free; |
| } |
| |
| enc_from = name_to_enc(interp, objv[2]); |
| if( !enc_from ) return TCL_ERROR; |
| enc_to = name_to_enc(interp, objv[3]); |
| if( !enc_to ) return TCL_ERROR; |
| |
| pVal = sqlite3ValueNew(0); |
| |
| if( enc_from==SQLITE_UTF8 ){ |
| z = Tcl_GetString(objv[1]); |
| if( objc==5 ){ |
| z = sqlite3_mprintf("%s", z); |
| } |
| sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel); |
| }else{ |
| z = (char*)Tcl_GetByteArrayFromObj(objv[1], &len); |
| if( objc==5 ){ |
| char *zTmp = z; |
| z = sqlite3_malloc(len); |
| memcpy(z, zTmp, len); |
| } |
| sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel); |
| } |
| |
| z = (char *)sqlite3ValueText(pVal, enc_to); |
| len = sqlite3ValueBytes(pVal, enc_to) + (enc_to==SQLITE_UTF8?1:2); |
| Tcl_SetObjResult(interp, Tcl_NewByteArrayObj((u8*)z, len)); |
| |
| sqlite3ValueFree(pVal); |
| |
| return TCL_OK; |
| } |
| |
| /* |
| ** Usage: translate_selftest |
| ** |
| ** Call sqlite3UtfSelfTest() to run the internal tests for unicode |
| ** translation. If there is a problem an assert() will fail. |
| **/ |
| void sqlite3UtfSelfTest(void); |
| static int SQLITE_TCLAPI test_translate_selftest( |
| void * clientData, |
| Tcl_Interp *interp, |
| int objc, |
| Tcl_Obj *CONST objv[] |
| ){ |
| #ifndef SQLITE_OMIT_UTF16 |
| sqlite3UtfSelfTest(); |
| #endif |
| return SQLITE_OK; |
| } |
| |
| |
| /* |
| ** Register commands with the TCL interpreter. |
| */ |
| int Sqlitetest5_Init(Tcl_Interp *interp){ |
| static struct { |
| char *zName; |
| Tcl_ObjCmdProc *xProc; |
| } aCmd[] = { |
| { "binarize", (Tcl_ObjCmdProc*)binarize }, |
| { "test_value_overhead", (Tcl_ObjCmdProc*)test_value_overhead }, |
| { "test_translate", (Tcl_ObjCmdProc*)test_translate }, |
| { "translate_selftest", (Tcl_ObjCmdProc*)test_translate_selftest}, |
| }; |
| int i; |
| for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
| Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
| } |
| return SQLITE_OK; |
| } |