From 85812533bfad9b933b29d7de418c5390dbdc549b Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Fri, 10 Jun 2011 09:41:46 -0700 Subject: [PATCH 001/124] Slightly tested UTF-8 support for Centrallix SQL Fixed all functions in Cenrallix's SQL language to support UTF-8. The character encoding is detected at startup and only the UTF-8 or the previous single-byte functions are registered. Also adding some initial support for mapping what the system calls certain character sets and what other software packages call them. --- centrallix/Makefile.in | 3 +- centrallix/centrallix.c | 17 + centrallix/etc/centrallix.conf.in | 1 + centrallix/expression/exp_functions.c | 3480 +++++++++++++------------ centrallix/include/centrallix.h | 10 +- 5 files changed, 1870 insertions(+), 1641 deletions(-) diff --git a/centrallix/Makefile.in b/centrallix/Makefile.in index 88b39f488..33a7a24cb 100644 --- a/centrallix/Makefile.in +++ b/centrallix/Makefile.in @@ -315,7 +315,8 @@ MODULES=$(OBJDRIVERMODULES) $(HTDRIVERMODULES) $(QYDRIVERMODULES) $(NETDRIVERMOD CONFFILES=centrallix.conf \ rootnode \ types.cfg \ - useragent.cfg + useragent.cfg \ + charsetmap.cfg # testobj-driven test files TOTESTFILES:=$(wildcard tests/test_$(TONLY)*.to) diff --git a/centrallix/centrallix.c b/centrallix/centrallix.c index 5f96e08b2..e979f79b7 100644 --- a/centrallix/centrallix.c +++ b/centrallix/centrallix.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -673,6 +675,21 @@ cxInitialize(void* v) CxGlobals.Flags = 0; xaInit(&CxGlobals.ShutdownHandlers,4); + /** Set the current locale to user's locale for chars **/ + setlocale(LC_CTYPE, ""); + + /** Check if UTF-8 or single byte encoding **/ + if(MB_CUR_MAX == 1) + CxGlobals.CharacterMode = CharModeSigleByte; + else if(strcmp(nl_langinfo(CODESET), "UTF-8") == 0) + CxGlobals.CharacterMode = CharModeUTF8; + else + { + fprintf(stderr, "Current locale is not single byte encoding or" + "UTF-8! Using C locale.\n"); + setlocale(LC_CTYPE, "C"); + } + /** set up the interrupt handler so we can shutdown properly **/ mtAddSignalHandler(SIGINT,cxShutdownThread); diff --git a/centrallix/etc/centrallix.conf.in b/centrallix/etc/centrallix.conf.in index 95ecc2226..c5733b081 100644 --- a/centrallix/etc/centrallix.conf.in +++ b/centrallix/etc/centrallix.conf.in @@ -11,6 +11,7 @@ centrallix "system/config" useragent_config = "##SYSCONFDIR##/centrallix/useragent.cfg"; rootnode_type = "system/uxfile"; rootnode_file = "##SYSCONFDIR##/centrallix/rootnode"; + charsetmap_file = "##SYSCONFDIR##/centrallix/charsetmap.cfg" iface_dir = "/sys/ifc"; // this is an OSML path theme_dir = "/sys/themes"; // OSML path transaction_log_file = "/var/log/cx_transaction_log"; diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index af5d247e0..1c3e87ee0 100644 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "obj.h" #include "cxlib/mtask.h" #include "cxlib/xarray.h" @@ -13,6 +15,7 @@ #include "cxlib/mtlexer.h" #include "expression.h" #include "cxlib/mtsession.h" +#include "centrallix.h" /************************************************************************/ /* Centrallix Application Server System */ @@ -193,1139 +196,943 @@ /****** Evaluator functions follow for expEvalFunction ******/ -int exp_fn_getdate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_getdate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { tree->DataType = DATA_T_DATETIME; objCurrentDate(&(tree->Types.Date)); return 0; - } +} -int exp_fn_user_name(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_user_name(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; tree->DataType = DATA_T_STRING; ptr = mssUserName(); - if (!ptr) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!ptr) { + tree->Flags |= EXPR_F_NULL; + return 0; + } tree->String = tree->Types.StringBuf; memccpy(tree->String, ptr, 0, 63); tree->String[63] = '\0'; return 0; - } +} - -int exp_fn_convert(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_convert(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { void* vptr; char* ptr; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i0->Flags & EXPR_F_NULL)) - { - mssError(1,"EXP","convert() requires data type and value to be converted"); - return -1; - } - switch(i1->DataType) - { - case DATA_T_INTEGER: vptr = &(i1->Integer); break; - case DATA_T_STRING: vptr = i1->String; break; - case DATA_T_DOUBLE: vptr = &(i1->Types.Double); break; - case DATA_T_DATETIME: vptr = &(i1->Types.Date); break; - case DATA_T_MONEY: vptr = &(i1->Types.Money); break; - default: - mssError(1,"EXP","convert(): unsupported arg 2 datatype"); - return -1; - } - if (!strcmp(i0->String,"integer")) - { - tree->DataType = DATA_T_INTEGER; - if (i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - tree->Integer = objDataToInteger(i1->DataType, vptr, NULL); - } - else if (!strcmp(i0->String,"string")) - { - tree->DataType = DATA_T_STRING; - if (i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - ptr = objDataToStringTmp(i1->DataType, vptr, 0); - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } - if (strlen(ptr) > 63) - { - tree->Alloc = 1; - tree->String = nmSysStrdup(ptr); - } - else - { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - strcpy(tree->String, ptr); - } - } - else if (!strcmp(i0->String,"double")) - { - tree->DataType = DATA_T_DOUBLE; - if (i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - tree->Types.Double = objDataToDouble(i1->DataType, vptr); - } - else if (!strcmp(i0->String,"money")) - { - tree->DataType = DATA_T_MONEY; - if (i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - objDataToMoney(i1->DataType, vptr, &(tree->Types.Money)); - } - else if (!strcmp(i0->String,"datetime")) - { - tree->DataType = DATA_T_DATETIME; - if (i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - objDataToDateTime(i1->DataType, vptr, &(tree->Types.Date), NULL); - } - else - { - mssError(1,"EXP","convert() datatype '%s' is invalid", i0->String); - } - return 0; + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i0->Flags & EXPR_F_NULL)) { + mssError(1, "EXP", "convert() requires data type and value to be converted"); + return -1; } + switch (i1->DataType) { + case DATA_T_INTEGER: vptr = &(i1->Integer); + break; + case DATA_T_STRING: vptr = i1->String; + break; + case DATA_T_DOUBLE: vptr = &(i1->Types.Double); + break; + case DATA_T_DATETIME: vptr = &(i1->Types.Date); + break; + case DATA_T_MONEY: vptr = &(i1->Types.Money); + break; + default: + mssError(1, "EXP", "convert(): unsupported arg 2 datatype"); + return -1; + } + if (!strcmp(i0->String, "integer")) { + tree->DataType = DATA_T_INTEGER; + if (i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + tree->Integer = objDataToInteger(i1->DataType, vptr, NULL); + } else if (!strcmp(i0->String, "string")) { + tree->DataType = DATA_T_STRING; + if (i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + ptr = objDataToStringTmp(i1->DataType, vptr, 0); + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } + if (strlen(ptr) > 63) { + tree->Alloc = 1; + tree->String = nmSysStrdup(ptr); + } else { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + strcpy(tree->String, ptr); + } + } else if (!strcmp(i0->String, "double")) { + tree->DataType = DATA_T_DOUBLE; + if (i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + tree->Types.Double = objDataToDouble(i1->DataType, vptr); + } else if (!strcmp(i0->String, "money")) { + tree->DataType = DATA_T_MONEY; + if (i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + objDataToMoney(i1->DataType, vptr, &(tree->Types.Money)); + } else if (!strcmp(i0->String, "datetime")) { + tree->DataType = DATA_T_DATETIME; + if (i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + objDataToDateTime(i1->DataType, vptr, &(tree->Types.Date), NULL); + } else { + mssError(1, "EXP", "convert() datatype '%s' is invalid", i0->String); + } + return 0; +} - -int exp_fn_wordify(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_wordify(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; tree->DataType = DATA_T_STRING; - if (!i0) - { - mssError(1,"EXP","Parameter required for wordify() function."); - return -1; - } - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - switch(i0->DataType) - { - case DATA_T_INTEGER: - ptr = objDataToWords(DATA_T_INTEGER, &(i0->Integer)); - break; - - case DATA_T_MONEY: - ptr = objDataToWords(DATA_T_MONEY, &(i0->Types.Money)); - break; - - default: - mssError(1,"EXP","Can only convert integer and money types with wordify()"); - return -1; - } - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } - if (strlen(ptr) > 63) - { - tree->String = nmSysStrdup(ptr); - tree->Alloc = 1; - } - else - { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; + if (!i0) { + mssError(1, "EXP", "Parameter required for wordify() function."); + return -1; + } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + switch (i0->DataType) { + case DATA_T_INTEGER: + ptr = objDataToWords(DATA_T_INTEGER, &(i0->Integer)); + break; + + case DATA_T_MONEY: + ptr = objDataToWords(DATA_T_MONEY, &(i0->Types.Money)); + break; + + default: + mssError(1, "EXP", "Can only convert integer and money types with wordify()"); + return -1; + } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } + if (strlen(ptr) > 63) { + tree->String = nmSysStrdup(ptr); + tree->Alloc = 1; + } else { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; strcpy(tree->String, ptr); - } - return 0; } + return 0; +} - -int exp_fn_abs(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!i0) - { - mssError(1,"EXP","Parameter required for abs() function."); - return -1; - } +int exp_fn_abs(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!i0) { + mssError(1, "EXP", "Parameter required for abs() function."); + return -1; + } tree->DataType = i0->DataType; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - } - else - { - switch(i0->DataType) - { - case DATA_T_INTEGER: - tree->Integer = abs(i0->Integer); - break; - - case DATA_T_DOUBLE: - tree->Types.Double = fabs(i0->Types.Double); - break; - - case DATA_T_MONEY: - if (i0->Types.Money.WholePart >= 0) - { - tree->Types.Money.WholePart = i0->Types.Money.WholePart; - tree->Types.Money.FractionPart = i0->Types.Money.FractionPart; - } - else - { - if (i0->Types.Money.FractionPart != 0) - { - tree->Types.Money.WholePart = -(i0->Types.Money.WholePart + 1); - tree->Types.Money.FractionPart = 10000 - i0->Types.Money.FractionPart; - } - else - { - tree->Types.Money.WholePart = -i0->Types.Money.WholePart; - tree->Types.Money.FractionPart = 0; - } - } - break; - - default: - mssError(1,"EXP","Invalid data type for abs() function"); - return -1; - } - } - return 0; + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + } else { + switch (i0->DataType) { + case DATA_T_INTEGER: + tree->Integer = abs(i0->Integer); + break; + + case DATA_T_DOUBLE: + tree->Types.Double = fabs(i0->Types.Double); + break; + + case DATA_T_MONEY: + if (i0->Types.Money.WholePart >= 0) { + tree->Types.Money.WholePart = i0->Types.Money.WholePart; + tree->Types.Money.FractionPart = i0->Types.Money.FractionPart; + } else { + if (i0->Types.Money.FractionPart != 0) { + tree->Types.Money.WholePart = -(i0->Types.Money.WholePart + 1); + tree->Types.Money.FractionPart = 10000 - i0->Types.Money.FractionPart; + } else { + tree->Types.Money.WholePart = -i0->Types.Money.WholePart; + tree->Types.Money.FractionPart = 0; + } + } + break; + + default: + mssError(1, "EXP", "Invalid data type for abs() function"); + return -1; + } } + return 0; +} - -int exp_fn_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { tree->DataType = DATA_T_INTEGER; - if (!i0) - { - mssError(1,"EXP","Parameter required for ascii() function."); - return -1; - } - if (i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","ascii() function takes a string parameter."); - return -1; - } + if (!i0) { + mssError(1, "EXP", "Parameter required for ascii() function."); + return -1; + } + if (i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "ascii() function takes a string parameter."); + return -1; + } if (i0->String[0] == '\0') - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; else - tree->Integer = i0->String[0]; + tree->Integer = i0->String[0]; return 0; - } +} -int exp_fn_condition(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!i0 || !i1 || !i2) - { - mssError(1,"EXP","Three parameters required for condition()"); - return -1; - } - if (exp_internal_EvalTree(i0,objlist) < 0) - { - return -1; - } - if (i0->DataType != DATA_T_INTEGER) - { - mssError(1,"EXP","condition() first parameter must evaluate to boolean"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) - { - tree->DataType = DATA_T_INTEGER; - tree->Flags |= EXPR_F_NULL; - i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); - i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); - return 0; - } - if (i0->Integer != 0) - { - /** True, return 2nd argument i1 **/ - i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); - if (exp_internal_EvalTree(i1,objlist) < 0) - { - return -1; - } - if (i2->AggLevel > 0) - if (exp_internal_EvalTree(i2,objlist) < 0) - return -1; - tree->DataType = i1->DataType; - if (i1->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - switch(i1->DataType) - { - case DATA_T_INTEGER: tree->Integer = i1->Integer; break; - case DATA_T_STRING: tree->String = i1->String; tree->Alloc = 0; break; - default: memcpy(&(tree->Types), &(i1->Types), sizeof(tree->Types)); break; - } - } - else - { - /** False, return 3rd argument i2 **/ - if (i1->AggLevel > 0) - { - if (exp_internal_EvalTree(i1,objlist) < 0) - return -1; - } - else - { - i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); - } - if (exp_internal_EvalTree(i2,objlist) < 0) - { - return -1; - } - tree->DataType = i2->DataType; - if (i2->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - switch(i2->DataType) - { - case DATA_T_INTEGER: tree->Integer = i2->Integer; break; - case DATA_T_STRING: tree->String = i2->String; tree->Alloc = 0; break; - default: memcpy(&(tree->Types), &(i2->Types), sizeof(tree->Types)); break; - } - } - return 0; +int exp_fn_condition(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!i0 || !i1 || !i2) { + mssError(1, "EXP", "Three parameters required for condition()"); + return -1; } + if (exp_internal_EvalTree(i0, objlist) < 0) { + return -1; + } + if (i0->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "condition() first parameter must evaluate to boolean"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) { + tree->DataType = DATA_T_INTEGER; + tree->Flags |= EXPR_F_NULL; + i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); + i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); + return 0; + } + if (i0->Integer != 0) { + /** True, return 2nd argument i1 **/ + i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); + if (exp_internal_EvalTree(i1, objlist) < 0) { + return -1; + } + if (i2->AggLevel > 0) + if (exp_internal_EvalTree(i2, objlist) < 0) + return -1; + tree->DataType = i1->DataType; + if (i1->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + switch (i1->DataType) { + case DATA_T_INTEGER: tree->Integer = i1->Integer; + break; + case DATA_T_STRING: tree->String = i1->String; + tree->Alloc = 0; + break; + default: memcpy(&(tree->Types), &(i1->Types), sizeof (tree->Types)); + break; + } + } else { + /** False, return 3rd argument i2 **/ + if (i1->AggLevel > 0) { + if (exp_internal_EvalTree(i1, objlist) < 0) + return -1; + } else { + i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); + } + if (exp_internal_EvalTree(i2, objlist) < 0) { + return -1; + } + tree->DataType = i2->DataType; + if (i2->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + switch (i2->DataType) { + case DATA_T_INTEGER: tree->Integer = i2->Integer; + break; + case DATA_T_STRING: tree->String = i2->String; + tree->Alloc = 0; + break; + default: memcpy(&(tree->Types), &(i2->Types), sizeof (tree->Types)); + break; + } + } + return 0; +} - -int exp_fn_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; tree->DataType = DATA_T_INTEGER; - if (!i0 || !i1) - { - mssError(1,"EXP","Two string parameters required for charindex()"); - return -1; - } - if ((i0->Flags | i1->Flags) & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) - { - mssError(1,"EXP","Two string parameters required for charindex()"); - return -1; - } + if (!i0 || !i1) { + mssError(1, "EXP", "Two string parameters required for charindex()"); + return -1; + } + if ((i0->Flags | i1->Flags) & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { + mssError(1, "EXP", "Two string parameters required for charindex()"); + return -1; + } ptr = strstr(i1->String, i0->String); if (ptr == NULL) - tree->Integer = 0; + tree->Integer = 0; else tree->Integer = (ptr - i1->String) + 1; return 0; - } - +} -int exp_fn_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - int n,i; +int exp_fn_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int n, i; tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","One string parameter required for upper()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for upper()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } n = strlen(i0->String); - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (n < 63) - { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } - else - { - tree->String = (char*)nmSysMalloc(n+1); - tree->Alloc = 1; - } - for(i=0;iString[i] >= 'a' && i0->String[i] <= 'z') tree->String[i] = i0->String[i] - 32; - else tree->String[i] = i0->String[i]; - } - return 0; + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + tree->Alloc = 0; } + if (n < 63) { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } else { + tree->String = (char*) nmSysMalloc(n + 1); + tree->Alloc = 1; + } + for (i = 0; i < n + 1; i++) { + if (i0->String[i] >= 'a' && i0->String[i] <= 'z') tree->String[i] = i0->String[i] - 32; + else tree->String[i] = i0->String[i]; + } + return 0; +} - -int exp_fn_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - int n,i; +int exp_fn_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int n, i; tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","One string parameter required for lower()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for lower()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } n = strlen(i0->String); - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (n < 63) - { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } - else - { - tree->String = (char*)nmSysMalloc(n+1); - tree->Alloc = 1; - } - for(i=0;iString[i] >= 'A' && i0->String[i] <= 'Z') tree->String[i] = i0->String[i] + 32; - else tree->String[i] = i0->String[i]; - } - return 0; + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + tree->Alloc = 0; } + if (n < 63) { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } else { + tree->String = (char*) nmSysMalloc(n + 1); + tree->Alloc = 1; + } + for (i = 0; i < n + 1; i++) { + if (i0->String[i] >= 'A' && i0->String[i] <= 'Z') tree->String[i] = i0->String[i] + 32; + else tree->String[i] = i0->String[i]; + } + return 0; +} - -int exp_fn_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { tree->DataType = DATA_T_INTEGER; - if (i0 && i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","One string parameter required for char_length()"); - return -1; - } + if (i0 && i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for char_length()"); + return -1; + } tree->Integer = strlen(i0->String); return 0; - } - +} -int exp_fn_datepart(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_datepart(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { pDateTime dtptr; DateTime dt; tree->DataType = DATA_T_INTEGER; - if (i0 && i1 && ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL))) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || !i1) - { - mssError(1,"EXP","datepart() requires two parameters"); - return -1; - } - if (i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","param 1 to datepart() must be month, day, year, hour, minute, or second"); - return -1; - } - if (i1->DataType == DATA_T_DATETIME) - { - dtptr = &(i1->Types.Date); - } - else if (i1->DataType == DATA_T_STRING) - { - if (objDataToDateTime(DATA_T_STRING, i1->String, &dt, NULL) < 0) - { - mssError(1,"EXP","in datepart(), failed to parse string date/time value"); - return -1; - } - dtptr = &dt; - } - else - { - mssError(1,"EXP","param 2 to datepart() must be a date/time value"); - return -1; - } - if (!strcasecmp(i0->String,"year")) - tree->Integer = dtptr->Part.Year + 1900; - else if (!strcasecmp(i0->String,"month")) + if (i0 && i1 && ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL))) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || !i1) { + mssError(1, "EXP", "datepart() requires two parameters"); + return -1; + } + if (i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "param 1 to datepart() must be month, day, year, hour, minute, or second"); + return -1; + } + if (i1->DataType == DATA_T_DATETIME) { + dtptr = &(i1->Types.Date); + } else if (i1->DataType == DATA_T_STRING) { + if (objDataToDateTime(DATA_T_STRING, i1->String, &dt, NULL) < 0) { + mssError(1, "EXP", "in datepart(), failed to parse string date/time value"); + return -1; + } + dtptr = &dt; + } else { + mssError(1, "EXP", "param 2 to datepart() must be a date/time value"); + return -1; + } + if (!strcasecmp(i0->String, "year")) + tree->Integer = dtptr->Part.Year + 1900; + else if (!strcasecmp(i0->String, "month")) tree->Integer = dtptr->Part.Month + 1; - else if (!strcasecmp(i0->String,"day")) + else if (!strcasecmp(i0->String, "day")) tree->Integer = dtptr->Part.Day + 1; - else if (!strcasecmp(i0->String,"hour")) + else if (!strcasecmp(i0->String, "hour")) tree->Integer = dtptr->Part.Hour; - else if (!strcasecmp(i0->String,"minute")) + else if (!strcasecmp(i0->String, "minute")) tree->Integer = dtptr->Part.Minute; - else if (!strcasecmp(i0->String,"second")) + else if (!strcasecmp(i0->String, "second")) tree->Integer = dtptr->Part.Second; - else - { - mssError(1,"EXP","param 1 to datepart() must be month, day, year, hour, minute, or second"); - return -1; - } - return 0; + else { + mssError(1, "EXP", "param 1 to datepart() must be month, day, year, hour, minute, or second"); + return -1; } + return 0; +} // Reverse isnull() just passes the value on to the first parameter, so the // isnull() function can be used to set default values on SQL query properties. -int exp_fn_reverse_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!i0) - { - mssError(1,"EXP","isnull() requires two parameters"); - return -1; - } - if (tree->Flags & EXPR_F_NULL) - i0->Flags |= EXPR_F_NULL; + +int exp_fn_reverse_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!i0) { + mssError(1, "EXP", "isnull() requires two parameters"); + return -1; + } + if (tree->Flags & EXPR_F_NULL) + i0->Flags |= EXPR_F_NULL; else - i0->Flags &= ~EXPR_F_NULL; - switch(tree->DataType) - { - case DATA_T_INTEGER: i0->Integer = tree->Integer; break; - case DATA_T_STRING: - if (i0->Alloc && i0->String) - { - nmSysFree(i0->String); - } - i0->Alloc = 0; - i0->String = tree->String; - break; - default: memcpy(&(i0->Types), &(tree->Types), sizeof(tree->Types)); break; - } + i0->Flags &= ~EXPR_F_NULL; + switch (tree->DataType) { + case DATA_T_INTEGER: i0->Integer = tree->Integer; + break; + case DATA_T_STRING: + if (i0->Alloc && i0->String) { + nmSysFree(i0->String); + } + i0->Alloc = 0; + i0->String = tree->String; + break; + default: memcpy(&(i0->Types), &(tree->Types), sizeof (tree->Types)); + break; + } i0->DataType = tree->DataType; return expReverseEvalTree(i0, objlist); - } +} -int exp_fn_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!i0 || !i1) - { - mssError(1,"EXP","isnull() requires two parameters"); - return -1; - } +int exp_fn_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!i0 || !i1) { + mssError(1, "EXP", "isnull() requires two parameters"); + return -1; + } if (i0->Flags & EXPR_F_NULL) i0 = i1; tree->DataType = i0->DataType; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - switch(i0->DataType) - { - case DATA_T_INTEGER: tree->Integer = i0->Integer; break; - case DATA_T_STRING: tree->String = i0->String; tree->Alloc = 0; break; - default: memcpy(&(tree->Types), &(i0->Types), sizeof(tree->Types)); - } - return 0; + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + switch (i0->DataType) { + case DATA_T_INTEGER: tree->Integer = i0->Integer; + break; + case DATA_T_STRING: tree->String = i0->String; + tree->Alloc = 0; + break; + default: memcpy(&(tree->Types), &(i0->Types), sizeof (tree->Types)); } + return 0; +} -int exp_fn_replicate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - int nl,n,l; +int exp_fn_replicate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int nl, n, l; char* ptr; int i; - - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) - { - mssError(1,"EXP","replicate() requires a string and a numeric parameter"); - return -1; - } - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL) || (i1->DataType == DATA_T_INTEGER && i1->Integer < 0) || (i1->DataType == DATA_T_DOUBLE && i1->Types.Double < 0)) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } + + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) { + mssError(1, "EXP", "replicate() requires a string and a numeric parameter"); + return -1; + } + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL) || (i1->DataType == DATA_T_INTEGER && i1->Integer < 0) || (i1->DataType == DATA_T_DOUBLE && i1->Types.Double < 0)) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } tree->DataType = DATA_T_STRING; - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } tree->Alloc = 0; - if (i1->DataType == DATA_T_INTEGER) - { - n = (i1->Integer > 255)?255:i1->Integer; - } - else - { - n = i1->Types.Double + 0.0001; - n = (n > 255)?255:n; - } - nl = strlen(i0->String)*n; - if (nl <= 63) - { - tree->String = tree->Types.StringBuf; - } - else - { - tree->Alloc = 1; - tree->String = nmSysMalloc(nl+1); - } + if (i1->DataType == DATA_T_INTEGER) { + n = (i1->Integer > 255) ? 255 : i1->Integer; + } else { + n = i1->Types.Double + 0.0001; + n = (n > 255) ? 255 : n; + } + nl = strlen(i0->String) * n; + if (nl <= 63) { + tree->String = tree->Types.StringBuf; + } else { + tree->Alloc = 1; + tree->String = nmSysMalloc(nl + 1); + } ptr = tree->String; l = strlen(i0->String); ptr[0] = '\0'; - if (l) for(i=0;iString); - ptr += l; - } + if (l) for (i = 0; i < n; i++) { + strcpy(ptr, i0->String); + ptr += l; + } return 0; - } +} - -int exp_fn_lztrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_lztrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; - if (!i0 || i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","lztrim() only works on STRING data types"); - return -1; - } - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } + if (!i0 || i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "lztrim() only works on STRING data types"); + return -1; + } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } tree->DataType = DATA_T_STRING; ptr = i0->String; - while(*ptr == '0' && (ptr[1] >= '0' && ptr[1] <= '9')) ptr++; + while (*ptr == '0' && (ptr[1] >= '0' && ptr[1] <= '9')) ptr++; tree->String = ptr; tree->Alloc = 0; return 0; - } +} - -int exp_fn_ltrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_ltrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; - if (!i0 || i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","ltrim() only works on STRING data types"); - return -1; - } - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } + if (!i0 || i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "ltrim() only works on STRING data types"); + return -1; + } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } tree->DataType = DATA_T_STRING; ptr = i0->String; - while(*ptr == ' ') ptr++; + while (*ptr == ' ') ptr++; tree->String = ptr; tree->Alloc = 0; return 0; - } +} - -int exp_fn_rtrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_rtrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; int n; - if (!i0 || i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING) - { - mssError(1,"EXP","rtrim() only works on STRING data types"); - return -1; - } - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } + if (!i0 || i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "rtrim() only works on STRING data types"); + return -1; + } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } tree->Alloc = 0; tree->DataType = DATA_T_STRING; ptr = i0->String + strlen(i0->String); - while(ptr > i0->String && ptr[-1] == ' ') ptr--; - if (ptr == i0->String + strlen(i0->String)) - { - /** optimization for strings are still the same **/ - tree->String = i0->String; - } - else - { - /** have to copy because we removed spaces **/ - n = ptr - i0->String; - if (n < 63) - { - tree->String = tree->Types.StringBuf; - memcpy(tree->String, i0->String, n); - tree->String[n] = '\0'; - tree->Alloc = 0; - } - else - { - tree->String = (char*)nmSysMalloc(n+1); - memcpy(tree->String, i0->String, n); - tree->String[n] = '\0'; - tree->Alloc = 1; - } - } - return 0; + while (ptr > i0->String && ptr[-1] == ' ') ptr--; + if (ptr == i0->String + strlen(i0->String)) { + /** optimization for strings are still the same **/ + tree->String = i0->String; + } else { + /** have to copy because we removed spaces **/ + n = ptr - i0->String; + if (n < 63) { + tree->String = tree->Types.StringBuf; + memcpy(tree->String, i0->String, n); + tree->String[n] = '\0'; + tree->Alloc = 0; + } else { + tree->String = (char*) nmSysMalloc(n + 1); + memcpy(tree->String, i0->String, n); + tree->String[n] = '\0'; + tree->Alloc = 1; + } } + return 0; +} +int exp_fn_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int n, i; -int exp_fn_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - int n,i; - - if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) - { - mssError(1,"EXP","Invalid datatypes in right() function - takes (string,integer)"); - return -1; - } - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - } + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "Invalid datatypes in right() function - takes (string,integer)"); + return -1; + } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } n = strlen(i0->String); i = i1->Integer; - if (i>n) i = n; + if (i > n) i = n; if (i < 0) i = 0; tree->DataType = DATA_T_STRING; tree->String = i0->String + (n - i); tree->Alloc = 0; return 0; - } - +} -int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - int i,n; +int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int i, n; char* ptr; - if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) - { - mssError(1,"EXP","Invalid datatypes in substring() - takes (string,integer,[integer])"); - return -1; - } - if (i2 && i2->DataType != DATA_T_INTEGER) - { - mssError(1,"EXP","Invalid datatypes in substring() - takes (string,integer,[integer])"); - return -1; - } + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } + if (i2 && i2->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } n = strlen(i0->String); - i = i1->Integer-1; - if (i<0) i = 0; + i = i1->Integer - 1; + if (i < 0) i = 0; if (i > n) i = n; ptr = i0->String + i; - i = i2?(i2->Integer):(strlen(ptr)); + i = i2 ? (i2->Integer) : (strlen(ptr)); if (i < 0) i = 0; if (i > strlen(ptr)) i = strlen(ptr); /** Ok, got position and length. Now make new string in tree-> **/ - if (tree->Alloc && tree->String) - { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (i<64) - { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } - else - { - tree->String = (char*)nmSysMalloc(i+1); - tree->Alloc = 1; - } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (i < 64) { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } else { + tree->String = (char*) nmSysMalloc(i + 1); + tree->Alloc = 1; + } memcpy(tree->String, ptr, i); tree->String[i] = '\0'; tree->DataType = DATA_T_STRING; return 0; - } - +} /*** Pad string expression i0 with integer expression i1 number of spaces ***/ -int exp_fn_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { int n; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) - { - mssError(1,"EXP","ralign() requires string parameter #1 and integer parameter #2"); - return -1; - } + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "ralign() requires string parameter #1 and integer parameter #2"); + return -1; + } tree->DataType = DATA_T_STRING; - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } n = strlen(i0->String); if (tree->Alloc && tree->String) nmSysFree(tree->String); - if (n >= i1->Integer) - { - tree->Alloc = 0; - tree->String = i0->String; - } - else - { - if (i1->Integer>=64) - { - tree->Alloc = 1; - tree->String = (char*)nmSysMalloc(i1->Integer+1); - } - else - { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } - sprintf(tree->String,"%*.*s",i1->Integer,i1->Integer,i0->String); - } - return 0; + if (n >= i1->Integer) { + tree->Alloc = 0; + tree->String = i0->String; + } else { + if (i1->Integer >= 64) { + tree->Alloc = 1; + tree->String = (char*) nmSysMalloc(i1->Integer + 1); + } else { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + sprintf(tree->String, "%*.*s", i1->Integer, i1->Integer, i0->String); } - + return 0; +} /** escape(string, escchars, badchars) **/ -int exp_fn_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* ptr; char* dst; char* escchars; - int esccnt,len; + int esccnt, len; tree->DataType = DATA_T_STRING; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) - { - mssError(1,"EXP","escape() requires two or three string parameters"); - return -1; - } - if (i2 && i2->DataType != DATA_T_STRING) - { - mssError(1,"EXP","the optional third escape() parameter must be a string"); - return -1; - } - if (i2 && !(i2->Flags & EXPR_F_NULL) && (ptr=strpbrk(i0->String, i2->String)) != NULL) - { - mssError(1,"EXP","WARNING!! String contains invalid character asc=%d", (int)(*ptr)); - return -1; - } - if ((i0->Flags & EXPR_F_NULL)) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { + mssError(1, "EXP", "escape() requires two or three string parameters"); + return -1; + } + if (i2 && i2->DataType != DATA_T_STRING) { + mssError(1, "EXP", "the optional third escape() parameter must be a string"); + return -1; + } + if (i2 && !(i2->Flags & EXPR_F_NULL) && (ptr = strpbrk(i0->String, i2->String)) != NULL) { + mssError(1, "EXP", "WARNING!! String contains invalid character asc=%d", (int) (*ptr)); + return -1; + } + if ((i0->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i1->Flags & EXPR_F_NULL) - escchars = ""; + escchars = ""; else - escchars = i1->String; + escchars = i1->String; if (tree->Alloc && tree->String) nmSysFree(tree->String); tree->Alloc = 0; ptr = strpbrk(i0->String, escchars); if (!ptr) ptr = strchr(i0->String, '\\'); - if (!ptr) - { - /** shortcut if no need to escape anything **/ - tree->Alloc = 0; - tree->String = i0->String; - return 0; - } + if (!ptr) { + /** shortcut if no need to escape anything **/ + tree->Alloc = 0; + tree->String = i0->String; + return 0; + } esccnt = 1; ptr++; - while(*ptr) - { - if (strchr(escchars, *ptr) || *ptr == '\\') esccnt++; - ptr++; - } + while (*ptr) { + if (strchr(escchars, *ptr) || *ptr == '\\') esccnt++; + ptr++; + } len = strlen(i0->String); - if (len+esccnt < 64) - { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } - else - { - tree->Alloc = 1; - tree->String = nmSysMalloc(len+esccnt+1); - } + if (len + esccnt < 64) { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } else { + tree->Alloc = 1; + tree->String = nmSysMalloc(len + esccnt + 1); + } ptr = i0->String; dst = tree->String; - while(*ptr) - { - if (strchr(escchars, *ptr) || *ptr == '\\') - *(dst++) = '\\'; - *(dst++) = *(ptr++); - } + while (*ptr) { + if (strchr(escchars, *ptr) || *ptr == '\\') + *(dst++) = '\\'; + *(dst++) = *(ptr++); + } *dst = '\0'; return 0; - } +} - -int exp_fn_quote(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - int len,quotecnt; +int exp_fn_quote(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int len, quotecnt; char* ptr; char* dst; tree->DataType = DATA_T_STRING; - if (i0 && (i0->Flags & EXPR_F_NULL)) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING || i1) - { - mssError(1,"EXP","quote() requires one string parameter"); - return -1; - } + if (i0 && (i0->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING || i1) { + mssError(1, "EXP", "quote() requires one string parameter"); + return -1; + } len = strlen(i0->String); ptr = i0->String; quotecnt = 0; - while(*ptr) - { - if (*ptr == '\\' || *ptr == '"') quotecnt++; - ptr++; - } + while (*ptr) { + if (*ptr == '\\' || *ptr == '"') quotecnt++; + ptr++; + } if (tree->Alloc && tree->String) nmSysFree(tree->String); tree->Alloc = 0; - if (len + quotecnt + 2 < 64) - { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } - else - { - tree->Alloc = 1; - tree->String = nmSysMalloc(len + quotecnt + 2 + 1); - } + if (len + quotecnt + 2 < 64) { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } else { + tree->Alloc = 1; + tree->String = nmSysMalloc(len + quotecnt + 2 + 1); + } ptr = i0->String; dst = tree->String; *(dst++) = '"'; - while(*ptr) - { - if (*ptr == '\\' || *ptr == '"') - *(dst++) = '\\'; - *(dst++) = *(ptr++); - } + while (*ptr) { + if (*ptr == '\\' || *ptr == '"') + *(dst++) = '\\'; + *(dst++) = *(ptr++); + } *(dst++) = '"'; *dst = '\0'; return 0; - } - +} -int exp_fn_eval(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_eval(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { pExpression eval_exp, parent; int rval; - if (i0 && !i1 && i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING || i1) - { - mssError(1,"EXP","eval() requires one string parameter"); - return -1; - } - for(parent=tree;parent->Parent;parent=parent->Parent); + if (i0 && !i1 && i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING || i1) { + mssError(1, "EXP", "eval() requires one string parameter"); + return -1; + } + for (parent = tree; parent->Parent; parent = parent->Parent); eval_exp = expCompileExpression(i0->String, objlist, parent->LxFlags, parent->CmpFlags); if (!eval_exp) return -1; - if ((rval=expEvalTree(eval_exp, objlist)) < 0) - { - expFreeExpression(eval_exp); - return -1; - } + if ((rval = expEvalTree(eval_exp, objlist)) < 0) { + expFreeExpression(eval_exp); + return -1; + } expCopyValue(eval_exp, tree, 1); expFreeExpression(eval_exp); return rval; - } +} - -int exp_fn_round(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_round(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { int dec = 0; int i, v; double dv; long long mt, mv; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) - { - mssError(1,"EXP","round() requires a numeric parameter and an optional integer parameter"); - return -1; - } - if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) { + mssError(1, "EXP", "round() requires a numeric parameter and an optional integer parameter"); + return -1; + } + if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i1) dec = i1->Integer; tree->DataType = i0->DataType; - switch(i0->DataType) - { - case DATA_T_INTEGER: - tree->Integer = i0->Integer; - if (dec < 0) - { - v = 1; - for(i=dec;i<0;i++) v *= 10; - if (tree->Integer > 0) - tree->Integer += (v/2); - else - tree->Integer -= (v/2); - tree->Integer /= v; - tree->Integer *= v; - } - break; - - case DATA_T_DOUBLE: - tree->Types.Double = i0->Types.Double; - dv = 1; - for(i=dec;i<0;i++) dv *= 10; - for(i=0;iTypes.Double = tree->Types.Double/dv; - if (tree->Types.Double > 0) - tree->Types.Double = floor(tree->Types.Double + 0.5); - else - tree->Types.Double = ceil(tree->Types.Double - 0.5); - tree->Types.Double = tree->Types.Double*dv; - break; - - case DATA_T_MONEY: - mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; - if (dec < 4) - { - mv = 1; - for(i=dec;i<4;i++) mv *= 10; - if (mt > 0) - mt += (mv/2); - else - mt -= (mv/2); - mt /= mv; - mt *= mv; - } - tree->Types.Money.WholePart = mt/10000; - mt = mt % 10000; - if (mt < 0) - { - mt += 10000; - tree->Types.Money.WholePart -= 1; - } - tree->Types.Money.FractionPart = mt; - break; - } - return 0; + switch (i0->DataType) { + case DATA_T_INTEGER: + tree->Integer = i0->Integer; + if (dec < 0) { + v = 1; + for (i = dec; i < 0; i++) v *= 10; + if (tree->Integer > 0) + tree->Integer += (v / 2); + else + tree->Integer -= (v / 2); + tree->Integer /= v; + tree->Integer *= v; + } + break; + + case DATA_T_DOUBLE: + tree->Types.Double = i0->Types.Double; + dv = 1; + for (i = dec; i < 0; i++) dv *= 10; + for (i = 0; i < dec; i++) dv /= 10; + tree->Types.Double = tree->Types.Double / dv; + if (tree->Types.Double > 0) + tree->Types.Double = floor(tree->Types.Double + 0.5); + else + tree->Types.Double = ceil(tree->Types.Double - 0.5); + tree->Types.Double = tree->Types.Double*dv; + break; + + case DATA_T_MONEY: + mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; + if (dec < 4) { + mv = 1; + for (i = dec; i < 4; i++) mv *= 10; + if (mt > 0) + mt += (mv / 2); + else + mt -= (mv / 2); + mt /= mv; + mt *= mv; + } + tree->Types.Money.WholePart = mt / 10000; + mt = mt % 10000; + if (mt < 0) { + mt += 10000; + tree->Types.Money.WholePart -= 1; + } + tree->Types.Money.FractionPart = mt; + break; } - + return 0; +} int -exp_fn_dateadd_mod_add(int v1, int v2, int mod, int* overflow) - { +exp_fn_dateadd_mod_add(int v1, int v2, int mod, int* overflow) { int rv; - rv = (v1 + v2)%mod; - *overflow = (v1 + v2)/mod; - if (rv < 0) - { - *overflow -= 1; - rv += mod; - } - return rv; + rv = (v1 + v2) % mod; + *overflow = (v1 + v2) / mod; + if (rv < 0) { + *overflow -= 1; + rv += mod; } + return rv; +} - -int exp_fn_dateadd(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_dateadd(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { int diff_sec, diff_min, diff_hr, diff_day, diff_mo, diff_yr; int carry; /** checks **/ - if (!i0 || (i0->Flags & EXPR_F_NULL) || i0->DataType != DATA_T_STRING) - { - mssError(1, "EXP", "dateadd() first parameter must be non-null string or keyword date part"); - return -1; - } - if ((i1 && (i1->Flags & EXPR_F_NULL)) || (i2 && (i2->Flags & EXPR_F_NULL))) - { - tree->DataType = DATA_T_DATETIME; - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i1 || i1->DataType != DATA_T_INTEGER) - { - mssError(1, "EXP", "dateadd() second parameter must be an integer (amount to add/subtract)"); - return -1; - } - if (!i2 || i2->DataType != DATA_T_DATETIME) - { - mssError(1, "EXP", "dateadd() third parameter must be a datetime type"); - return -1; - } + if (!i0 || (i0->Flags & EXPR_F_NULL) || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "dateadd() first parameter must be non-null string or keyword date part"); + return -1; + } + if ((i1 && (i1->Flags & EXPR_F_NULL)) || (i2 && (i2->Flags & EXPR_F_NULL))) { + tree->DataType = DATA_T_DATETIME; + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i1 || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "dateadd() second parameter must be an integer (amount to add/subtract)"); + return -1; + } + if (!i2 || i2->DataType != DATA_T_DATETIME) { + mssError(1, "EXP", "dateadd() third parameter must be a datetime type"); + return -1; + } /** ok, we're good. set up for returning the value **/ tree->DataType = DATA_T_DATETIME; - memcpy(&tree->Types.Date, &i2->Types.Date, sizeof(DateTime)); + memcpy(&tree->Types.Date, &i2->Types.Date, sizeof (DateTime)); diff_sec = diff_min = diff_hr = diff_day = diff_mo = diff_yr = 0; if (!strcmp(i0->String, "second")) - diff_sec = i1->Integer; + diff_sec = i1->Integer; else if (!strcmp(i0->String, "minute")) - diff_min = i1->Integer; + diff_min = i1->Integer; else if (!strcmp(i0->String, "hour")) - diff_hr = i1->Integer; + diff_hr = i1->Integer; else if (!strcmp(i0->String, "day")) - diff_day = i1->Integer; + diff_day = i1->Integer; else if (!strcmp(i0->String, "month")) - diff_mo = i1->Integer; + diff_mo = i1->Integer; else if (!strcmp(i0->String, "year")) - diff_yr = i1->Integer; - else - { - mssError(1, "EXP", "dateadd() first parameter must be a valid date part (second/minute/hour/day/month/year)"); - return -1; - } + diff_yr = i1->Integer; + else { + mssError(1, "EXP", "dateadd() first parameter must be a valid date part (second/minute/hour/day/month/year)"); + return -1; + } /** Do the add **/ tree->Types.Date.Part.Second = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Second, diff_sec, 60, &carry); @@ -1341,889 +1148,1284 @@ int exp_fn_dateadd(pExpression tree, pParamObjects objlist, pExpression i0, pExp tree->Types.Date.Part.Year += diff_yr; /** Adding days is more complicated **/ - while (diff_day > 0) - { - if (tree->Types.Date.Part.Day >= (obj_month_days[tree->Types.Date.Part.Month] + ((tree->Types.Date.Part.Month==1 && IS_LEAP_YEAR(tree->Types.Date.Part.Year+1900))?1:0))) - { - tree->Types.Date.Part.Day = 0; - tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, 1, 12, &carry); - tree->Types.Date.Part.Year += carry; - } - else - { - tree->Types.Date.Part.Day++; - } - diff_day--; - } - while (diff_day < 0) - { - if (tree->Types.Date.Part.Day == 0) - { - tree->Types.Date.Part.Day = (obj_month_days[exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry)] + ((tree->Types.Date.Part.Month==2 && IS_LEAP_YEAR(tree->Types.Date.Part.Year+1900))?1:0)) - 1; - tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry); - tree->Types.Date.Part.Year += carry; - } - else - { - tree->Types.Date.Part.Day--; - } - diff_day++; - } - - return 0; + while (diff_day > 0) { + if (tree->Types.Date.Part.Day >= (obj_month_days[tree->Types.Date.Part.Month] + ((tree->Types.Date.Part.Month == 1 && IS_LEAP_YEAR(tree->Types.Date.Part.Year + 1900)) ? 1 : 0))) { + tree->Types.Date.Part.Day = 0; + tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, 1, 12, &carry); + tree->Types.Date.Part.Year += carry; + } else { + tree->Types.Date.Part.Day++; + } + diff_day--; + } + while (diff_day < 0) { + if (tree->Types.Date.Part.Day == 0) { + tree->Types.Date.Part.Day = (obj_month_days[exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry)] + ((tree->Types.Date.Part.Month == 2 && IS_LEAP_YEAR(tree->Types.Date.Part.Year + 1900)) ? 1 : 0)) - 1; + tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry); + tree->Types.Date.Part.Year += carry; + } else { + tree->Types.Date.Part.Day--; + } + diff_day++; } + return 0; +} -int exp_fn_truncate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_truncate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { int dec = 0; int i, v; double dv; long long mt, mv; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) - { - mssError(1,"EXP","truncate() requires a numeric parameter and an optional integer parameter"); - return -1; - } - if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) { + mssError(1, "EXP", "truncate() requires a numeric parameter and an optional integer parameter"); + return -1; + } + if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i1) dec = i1->Integer; tree->DataType = i0->DataType; - switch(i0->DataType) - { - case DATA_T_INTEGER: - tree->Integer = i0->Integer; - if (dec < 0) - { - v = 1; - for(i=dec;i<0;i++) v *= 10; - tree->Integer /= v; - tree->Integer *= v; - } - break; - - case DATA_T_DOUBLE: - tree->Types.Double = i0->Types.Double; - dv = 1; - for(i=dec;i<0;i++) dv *= 10; - for(i=0;iTypes.Double = tree->Types.Double/dv; - if (tree->Types.Double > 0) - tree->Types.Double = floor(tree->Types.Double + 0.000001); - else - tree->Types.Double = ceil(tree->Types.Double - 0.000001); - tree->Types.Double = tree->Types.Double*dv; - break; - - case DATA_T_MONEY: - mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; - if (dec < 4) - { - mv = 1; - for(i=dec;i<4;i++) mv *= 10; - mt /= mv; - mt *= mv; - } - tree->Types.Money.WholePart = mt/10000; - mt = mt % 10000; - if (mt < 0) - { - mt += 10000; - tree->Types.Money.WholePart -= 1; - } - tree->Types.Money.FractionPart = mt; - break; - } - return 0; + switch (i0->DataType) { + case DATA_T_INTEGER: + tree->Integer = i0->Integer; + if (dec < 0) { + v = 1; + for (i = dec; i < 0; i++) v *= 10; + tree->Integer /= v; + tree->Integer *= v; + } + break; + + case DATA_T_DOUBLE: + tree->Types.Double = i0->Types.Double; + dv = 1; + for (i = dec; i < 0; i++) dv *= 10; + for (i = 0; i < dec; i++) dv /= 10; + tree->Types.Double = tree->Types.Double / dv; + if (tree->Types.Double > 0) + tree->Types.Double = floor(tree->Types.Double + 0.000001); + else + tree->Types.Double = ceil(tree->Types.Double - 0.000001); + tree->Types.Double = tree->Types.Double*dv; + break; + + case DATA_T_MONEY: + mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; + if (dec < 4) { + mv = 1; + for (i = dec; i < 4; i++) mv *= 10; + mt /= mv; + mt *= mv; + } + tree->Types.Money.WholePart = mt / 10000; + mt = mt % 10000; + if (mt < 0) { + mt += 10000; + tree->Types.Money.WholePart -= 1; + } + tree->Types.Money.FractionPart = mt; + break; } + return 0; +} /*** constrain(value, min, max) ***/ -int exp_fn_constrain(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!i0 || !i1 || !i2 || (i0->DataType != i1->DataType) || i0->DataType != i2->DataType || !(i0->DataType == DATA_T_INTEGER || i0->DataType == DATA_T_MONEY || i0->DataType == DATA_T_DOUBLE)) - { - mssError(1,"EXP","constrain() requires three numeric parameters of the same data type"); - return -1; - } +int exp_fn_constrain(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!i0 || !i1 || !i2 || (i0->DataType != i1->DataType) || i0->DataType != i2->DataType || !(i0->DataType == DATA_T_INTEGER || i0->DataType == DATA_T_MONEY || i0->DataType == DATA_T_DOUBLE)) { + mssError(1, "EXP", "constrain() requires three numeric parameters of the same data type"); + return -1; + } tree->DataType = i0->DataType; - if ((i0->Flags & EXPR_F_NULL)) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if ((i0->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } /* check min */ - if (!(i1->Flags & EXPR_F_NULL)) - { - switch(i0->DataType) - { - case DATA_T_INTEGER: - if (objDataCompare(i0->DataType, &(i0->Integer), i1->DataType, &(i1->Integer)) < 0) - { - tree->Integer = i1->Integer; - return 0; - } - break; - case DATA_T_DOUBLE: - if (objDataCompare(i0->DataType, &(i0->Types.Double), i1->DataType, &(i1->Types.Double)) < 0) - { - tree->Types.Double = i1->Types.Double; - return 0; - } - break; - case DATA_T_MONEY: - if (objDataCompare(i0->DataType, &(i0->Types.Money), i1->DataType, &(i1->Types.Money)) < 0) - { - tree->Types.Money = i1->Types.Money; - return 0; - } - break; - } - } + if (!(i1->Flags & EXPR_F_NULL)) { + switch (i0->DataType) { + case DATA_T_INTEGER: + if (objDataCompare(i0->DataType, &(i0->Integer), i1->DataType, &(i1->Integer)) < 0) { + tree->Integer = i1->Integer; + return 0; + } + break; + case DATA_T_DOUBLE: + if (objDataCompare(i0->DataType, &(i0->Types.Double), i1->DataType, &(i1->Types.Double)) < 0) { + tree->Types.Double = i1->Types.Double; + return 0; + } + break; + case DATA_T_MONEY: + if (objDataCompare(i0->DataType, &(i0->Types.Money), i1->DataType, &(i1->Types.Money)) < 0) { + tree->Types.Money = i1->Types.Money; + return 0; + } + break; + } + } /* check max */ - if (!(i2->Flags & EXPR_F_NULL)) - { - switch(i0->DataType) - { - case DATA_T_INTEGER: - if (objDataCompare(i0->DataType, &(i0->Integer), i2->DataType, &(i2->Integer)) > 0) - { - tree->Integer = i2->Integer; - return 0; - } - break; - case DATA_T_DOUBLE: - if (objDataCompare(i0->DataType, &(i0->Types.Double), i2->DataType, &(i2->Types.Double)) > 0) - { - tree->Types.Double = i2->Types.Double; - return 0; - } - break; - case DATA_T_MONEY: - if (objDataCompare(i0->DataType, &(i0->Types.Money), i2->DataType, &(i2->Types.Money)) > 0) - { - tree->Types.Money = i2->Types.Money; - return 0; - } - break; - } - } + if (!(i2->Flags & EXPR_F_NULL)) { + switch (i0->DataType) { + case DATA_T_INTEGER: + if (objDataCompare(i0->DataType, &(i0->Integer), i2->DataType, &(i2->Integer)) > 0) { + tree->Integer = i2->Integer; + return 0; + } + break; + case DATA_T_DOUBLE: + if (objDataCompare(i0->DataType, &(i0->Types.Double), i2->DataType, &(i2->Types.Double)) > 0) { + tree->Types.Double = i2->Types.Double; + return 0; + } + break; + case DATA_T_MONEY: + if (objDataCompare(i0->DataType, &(i0->Types.Money), i2->DataType, &(i2->Types.Money)) > 0) { + tree->Types.Money = i2->Types.Money; + return 0; + } + break; + } + } /* go with actual value */ - switch(i0->DataType) - { - case DATA_T_INTEGER: - tree->Integer = i0->Integer; - break; - case DATA_T_DOUBLE: - tree->Types.Double = i0->Types.Double; - break; - case DATA_T_MONEY: - tree->Types.Money = i0->Types.Money; - break; - } - - return 0; + switch (i0->DataType) { + case DATA_T_INTEGER: + tree->Integer = i0->Integer; + break; + case DATA_T_DOUBLE: + tree->Types.Double = i0->Types.Double; + break; + case DATA_T_MONEY: + tree->Types.Money = i0->Types.Money; + break; } + return 0; +} -int exp_fn_radians(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_radians(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; double pi = 3.14159265358979323846; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","radians() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "radians() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; - tree->Types.Double = d*pi/180.0; + d = i0->Types.Double; + tree->Types.Double = d * pi / 180.0; return 0; - } +} -int exp_fn_degrees(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_degrees(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; double pi = 3.14159265358979323846; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","degrees() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "degrees() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; - tree->Types.Double = d*180.0/pi; + d = i0->Types.Double; + tree->Types.Double = d * 180.0 / pi; return 0; - } - +} -int exp_fn_sin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_sin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","sin() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "sin() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; tree->Types.Double = sin(d); return 0; - } +} - -int exp_fn_cos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_cos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","cos() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "cos() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; tree->Types.Double = cos(d); return 0; - } +} - -int exp_fn_tan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_tan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","tan() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "tan() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; tree->Types.Double = tan(d); return 0; - } - +} -int exp_fn_asin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_asin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","asin() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "asin() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = asin(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; - } - +} -int exp_fn_acos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_acos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","acos() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "acos() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = acos(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; - } +} - -int exp_fn_atan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_atan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","atan() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "atan() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = atan(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; - } - +} -int exp_fn_atan2(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_atan2(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d1, d2; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || !i1 || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) - { - mssError(1,"EXP","atan2() requires two numeric (integer or double) parameters"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || !i1 || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) { + mssError(1, "EXP", "atan2() requires two numeric (integer or double) parameters"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d1 = i0->Integer; + d1 = i0->Integer; else - d1 = i0->Types.Double; + d1 = i0->Types.Double; if (i1->DataType == DATA_T_INTEGER) - d2 = i1->Integer; + d2 = i1->Integer; else - d2 = i1->Types.Double; + d2 = i1->Types.Double; errno = 0; tree->Types.Double = atan2(d1, d2); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; - } - +} -int exp_fn_sqrt(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_sqrt(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","sqrt() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "sqrt() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = sqrt(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; - } +} - -int exp_fn_square(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) - { - mssError(1,"EXP","square() requires a single numeric (integer or double) parameter"); - return -1; - } +int exp_fn_square(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { + mssError(1, "EXP", "square() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = i0->DataType; - if (i0->Flags & EXPR_F_NULL) - { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - tree->Integer = i0->Integer * i0->Integer; + tree->Integer = i0->Integer * i0->Integer; else - tree->Types.Double = i0->Types.Double * i0->Types.Double; + tree->Types.Double = i0->Types.Double * i0->Types.Double; return 0; - } +} - -int exp_fn_count(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_count(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { pExpression new_exp; /** Init the Aggregate computation expression? **/ - if (!tree->AggExp) - { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_PLUS; - tree->AggExp->DataType = DATA_T_INTEGER; - tree->AggExp->Integer = 0; - tree->AggExp->AggLevel = 1; - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->DataType = DATA_T_INTEGER; - new_exp->Integer = 1; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - } + if (!tree->AggExp) { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_PLUS; + tree->AggExp->DataType = DATA_T_INTEGER; + tree->AggExp->Integer = 0; + tree->AggExp->AggLevel = 1; + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->DataType = DATA_T_INTEGER; + new_exp->Integer = 1; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + } if (tree->Flags & EXPR_F_AGGLOCKED) return 0; /** Compute the possibly incremented value **/ - if (!(i0->Flags & EXPR_F_NULL)) - { - expCopyValue(tree->AggExp, (pExpression)(tree->AggExp->Children.Items[1]), 0); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 0); - } + if (!(i0->Flags & EXPR_F_NULL)) { + expCopyValue(tree->AggExp, (pExpression) (tree->AggExp->Children.Items[1]), 0); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 0); + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; - } - +} -int exp_fn_avg(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_avg(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { pExpression new_exp, new_subexp; pExpression sumexp, cntexp, s_accumexp, c_accumexp, valueexp; /** Init the Aggregate computation expression? **/ - if (!tree->AggExp) - { - /** Overall expression is sum(x) / count(x) **/ - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_DIVIDE; - tree->AggExp->DataType = DATA_T_INTEGER; - tree->AggExp->Integer = 0; - tree->AggExp->AggLevel = 1; - tree->AggExp->Flags |= EXPR_F_NULL; - - /** Now for the sum(x) part **/ - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_PLUS; - new_exp->DataType = DATA_T_INTEGER; - new_exp->Integer = 0; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - - /** Now for the count(x) part **/ - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_PLUS; - new_exp->DataType = DATA_T_INTEGER; - new_exp->Integer = 0; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->DataType = DATA_T_INTEGER; - new_subexp->Integer = 1; - new_subexp->AggLevel = 1; - expAddNode(new_exp,new_subexp); - } - - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) - { - /** Just to make things easier to read... **/ - sumexp = (pExpression)(tree->AggExp->Children.Items[0]); - cntexp = (pExpression)(tree->AggExp->Children.Items[1]); - s_accumexp = (pExpression)(sumexp->Children.Items[0]); - valueexp = (pExpression)(sumexp->Children.Items[1]); - c_accumexp = (pExpression)(cntexp->Children.Items[0]); - - /** Init the sum() part? **/ - if (tree->AggCount == 0) - { - tree->AggExp->Flags &= ~EXPR_F_NULL; - sumexp->DataType = i0->DataType; - sumexp->String = sumexp->Types.StringBuf; - sumexp->Alloc = 0; - sumexp->String[0] = '\0'; - sumexp->Integer = 0; - sumexp->Types.Double = 0; - sumexp->Types.Money.FractionPart = 0; - sumexp->Types.Money.WholePart = 0; - - cntexp->Integer = 0; - } - - /** Do the count() part. **/ - expCopyValue(cntexp, c_accumexp, 0); - - /** Do the sum() part. **/ - expCopyValue(sumexp, s_accumexp, 1); - expCopyValue(i0, valueexp, 0); - valueexp->NodeType = expDataTypeToNodeType(i0->DataType); - s_accumexp->NodeType = expDataTypeToNodeType(sumexp->DataType); - - /** Eval the expression and copy the result. **/ - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - - /** - switch(i0->DataType) - { - case DATA_T_INTEGER: - tree->DataType = DATA_T_INTEGER; - tree->AggCount++; - tree->AggExp->Integer += i0->Integer; - tree->Integer = tree->AggExp->Integer / tree->AggCount; - break; - case DATA_T_DOUBLE: - tree->DataType = DATA_T_DOUBLE; - tree->AggCount++; - tree->AggExp->Types.Double += i0->Types.Double; - tree->Types.Double = tree->AggExp->Types.Double / tree->AggCount; - break; - } - **/ - } - else - { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; - return 0; + if (!tree->AggExp) { + /** Overall expression is sum(x) / count(x) **/ + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_DIVIDE; + tree->AggExp->DataType = DATA_T_INTEGER; + tree->AggExp->Integer = 0; + tree->AggExp->AggLevel = 1; + tree->AggExp->Flags |= EXPR_F_NULL; + + /** Now for the sum(x) part **/ + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_PLUS; + new_exp->DataType = DATA_T_INTEGER; + new_exp->Integer = 0; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); + + /** Now for the count(x) part **/ + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_PLUS; + new_exp->DataType = DATA_T_INTEGER; + new_exp->Integer = 0; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->DataType = DATA_T_INTEGER; + new_subexp->Integer = 1; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); } + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { + /** Just to make things easier to read... **/ + sumexp = (pExpression) (tree->AggExp->Children.Items[0]); + cntexp = (pExpression) (tree->AggExp->Children.Items[1]); + s_accumexp = (pExpression) (sumexp->Children.Items[0]); + valueexp = (pExpression) (sumexp->Children.Items[1]); + c_accumexp = (pExpression) (cntexp->Children.Items[0]); + + /** Init the sum() part? **/ + if (tree->AggCount == 0) { + tree->AggExp->Flags &= ~EXPR_F_NULL; + sumexp->DataType = i0->DataType; + sumexp->String = sumexp->Types.StringBuf; + sumexp->Alloc = 0; + sumexp->String[0] = '\0'; + sumexp->Integer = 0; + sumexp->Types.Double = 0; + sumexp->Types.Money.FractionPart = 0; + sumexp->Types.Money.WholePart = 0; + + cntexp->Integer = 0; + } + + /** Do the count() part. **/ + expCopyValue(cntexp, c_accumexp, 0); + + /** Do the sum() part. **/ + expCopyValue(sumexp, s_accumexp, 1); + expCopyValue(i0, valueexp, 0); + valueexp->NodeType = expDataTypeToNodeType(i0->DataType); + s_accumexp->NodeType = expDataTypeToNodeType(sumexp->DataType); + + /** Eval the expression and copy the result. **/ + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + + /** + switch(i0->DataType) + { + case DATA_T_INTEGER: + tree->DataType = DATA_T_INTEGER; + tree->AggCount++; + tree->AggExp->Integer += i0->Integer; + tree->Integer = tree->AggExp->Integer / tree->AggCount; + break; + case DATA_T_DOUBLE: + tree->DataType = DATA_T_DOUBLE; + tree->AggCount++; + tree->AggExp->Types.Double += i0->Types.Double; + tree->Types.Double = tree->AggExp->Types.Double / tree->AggCount; + break; + } + **/ + } else { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } + tree->Flags |= EXPR_F_AGGLOCKED; + return 0; +} -int exp_fn_sum(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { +int exp_fn_sum(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { pExpression new_exp; - if (!tree->AggExp) - { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_PLUS; - tree->AggExp->DataType = DATA_T_INTEGER; - tree->AggExp->Integer = 0; - tree->AggExp->AggLevel = 1; - tree->AggExp->Flags |= EXPR_F_NULL; - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - } + if (!tree->AggExp) { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_PLUS; + tree->AggExp->DataType = DATA_T_INTEGER; + tree->AggExp->Integer = 0; + tree->AggExp->AggLevel = 1; + tree->AggExp->Flags |= EXPR_F_NULL; + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + } /*if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL;*/ - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) - { - if (tree->AggCount == 0) - { - tree->AggExp->Flags &= ~EXPR_F_NULL; - tree->AggExp->DataType = i0->DataType; - if (tree->AggExp->Alloc && tree->AggExp->String) nmSysFree(tree->AggExp->String); - tree->AggExp->Alloc = 0; - tree->AggExp->String = tree->AggExp->Types.StringBuf; - tree->AggExp->String[0] = '\0'; - tree->AggExp->Integer = 0; - tree->AggExp->Types.Double = 0; - tree->AggExp->Types.Money.FractionPart = 0; - tree->AggExp->Types.Money.WholePart = 0; - } - expCopyValue(tree->AggExp, (pExpression)(tree->AggExp->Children.Items[0]), 1); - expCopyValue(i0, (pExpression)(tree->AggExp->Children.Items[1]), 0); - ((pExpression)(tree->AggExp->Children.Items[1]))->NodeType = expDataTypeToNodeType(i0->DataType); - ((pExpression)(tree->AggExp->Children.Items[0]))->NodeType = expDataTypeToNodeType(tree->AggExp->DataType); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - } - else - { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { + if (tree->AggCount == 0) { + tree->AggExp->Flags &= ~EXPR_F_NULL; + tree->AggExp->DataType = i0->DataType; + if (tree->AggExp->Alloc && tree->AggExp->String) nmSysFree(tree->AggExp->String); + tree->AggExp->Alloc = 0; + tree->AggExp->String = tree->AggExp->Types.StringBuf; + tree->AggExp->String[0] = '\0'; + tree->AggExp->Integer = 0; + tree->AggExp->Types.Double = 0; + tree->AggExp->Types.Money.FractionPart = 0; + tree->AggExp->Types.Money.WholePart = 0; + } + expCopyValue(tree->AggExp, (pExpression) (tree->AggExp->Children.Items[0]), 1); + expCopyValue(i0, (pExpression) (tree->AggExp->Children.Items[1]), 0); + ((pExpression) (tree->AggExp->Children.Items[1]))->NodeType = expDataTypeToNodeType(i0->DataType); + ((pExpression) (tree->AggExp->Children.Items[0]))->NodeType = expDataTypeToNodeType(tree->AggExp->DataType); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + } else { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; +} + +int exp_fn_max(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + pExpression exp, subexp; + + /** Initialize the aggexp tree? **/ + if (!tree->AggExp) { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_FUNCTION; + tree->AggExp->AggLevel = 1; + tree->AggExp->Name = "condition"; + tree->AggExp->NameAlloc = 0; + tree->AggExp->Flags |= EXPR_F_NULL; + exp = expAllocExpression(); + exp->NodeType = EXPR_N_COMPARE; + exp->CompareType = MLX_CMP_GREATER; + exp->AggLevel = 1; + subexp = expAllocExpression(); + subexp->AggLevel = 1; + expAddNode(tree->AggExp, exp); + expAddNode(tree->AggExp, expLinkExpression(i0)); + expAddNode(tree->AggExp, subexp); + expAddNode(exp, expLinkExpression(i0)); + expAddNode(exp, expLinkExpression(subexp)); } + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { + if (tree->AggCount == 0) { + tree->AggExp->Flags &= ~EXPR_F_NULL; + tree->DataType = i0->DataType; + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + tree->String[0] = '\0'; + tree->Integer = 0; + tree->Types.Double = 0; + tree->Types.Money.FractionPart = 0; + tree->Types.Money.WholePart = 0; + expCopyValue(i0, tree, 0); + } + subexp = ((pExpression) (tree->AggExp->Children.Items[2])); + subexp->NodeType = expDataTypeToNodeType(i0->DataType); + expCopyValue(tree, subexp, 1); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + } else { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } + tree->Flags |= EXPR_F_AGGLOCKED; + return 0; +} -int exp_fn_max(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - pExpression exp,subexp; +int exp_fn_min(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + pExpression exp, subexp; /** Initialize the aggexp tree? **/ - if (!tree->AggExp) - { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_FUNCTION; - tree->AggExp->AggLevel = 1; - tree->AggExp->Name = "condition"; - tree->AggExp->NameAlloc = 0; - tree->AggExp->Flags |= EXPR_F_NULL; - exp = expAllocExpression(); - exp->NodeType = EXPR_N_COMPARE; - exp->CompareType = MLX_CMP_GREATER; - exp->AggLevel = 1; - subexp = expAllocExpression(); - subexp->AggLevel = 1; - expAddNode(tree->AggExp, exp); - expAddNode(tree->AggExp, expLinkExpression(i0)); - expAddNode(tree->AggExp, subexp); - expAddNode(exp, expLinkExpression(i0)); - expAddNode(exp, expLinkExpression(subexp)); - } - - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) - { - if (tree->AggCount == 0) - { - tree->AggExp->Flags &= ~EXPR_F_NULL; - tree->DataType = i0->DataType; - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - tree->String[0] = '\0'; - tree->Integer = 0; - tree->Types.Double = 0; - tree->Types.Money.FractionPart = 0; - tree->Types.Money.WholePart = 0; - expCopyValue(i0,tree,0); - } - subexp = ((pExpression)(tree->AggExp->Children.Items[2])); - subexp->NodeType = expDataTypeToNodeType(i0->DataType); - expCopyValue(tree, subexp, 1); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - } - else - { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } + if (!tree->AggExp) { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_FUNCTION; + tree->AggExp->AggLevel = 1; + tree->AggExp->Name = "condition"; + tree->AggExp->NameAlloc = 0; + tree->AggExp->Flags |= EXPR_F_NULL; + exp = expAllocExpression(); + exp->NodeType = EXPR_N_COMPARE; + exp->CompareType = MLX_CMP_LESS; + exp->AggLevel = 1; + subexp = expAllocExpression(); + subexp->AggLevel = 1; + expAddNode(tree->AggExp, exp); + expAddNode(tree->AggExp, expLinkExpression(i0)); + expAddNode(tree->AggExp, subexp); + expAddNode(exp, expLinkExpression(i0)); + expAddNode(exp, expLinkExpression(subexp)); + } + + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { + if (tree->AggCount == 0) { + tree->AggExp->Flags &= ~EXPR_F_NULL; + tree->DataType = i0->DataType; + tree->String = tree->Types.StringBuf; + tree->String[0] = '\0'; + tree->Alloc = 0; + tree->Integer = 0; + tree->Types.Double = 0; + tree->Types.Money.FractionPart = 0; + tree->Types.Money.WholePart = 0; + expCopyValue(i0, tree, 0); + } + subexp = ((pExpression) (tree->AggExp->Children.Items[2])); + subexp->NodeType = expDataTypeToNodeType(i0->DataType); + expCopyValue(tree, subexp, 1); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + } else { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } + tree->Flags |= EXPR_F_AGGLOCKED; + return 0; +} + +int exp_fn_first(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) { + if (tree->AggCount == 0) { + expCopyValue(i0, tree, 1); + } + tree->AggCount++; + } else { + if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; +} + +int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) { + expCopyValue(i0, tree, 1); + tree->AggCount++; + } else { + if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; } + tree->Flags |= EXPR_F_AGGLOCKED; + return 0; +} -int exp_fn_min(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - pExpression exp,subexp; +int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + wchar_t firstChar; + size_t bytesParsed; - /** Initialize the aggexp tree? **/ - if (!tree->AggExp) - { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_FUNCTION; - tree->AggExp->AggLevel = 1; - tree->AggExp->Name = "condition"; - tree->AggExp->NameAlloc = 0; - tree->AggExp->Flags |= EXPR_F_NULL; - exp = expAllocExpression(); - exp->NodeType = EXPR_N_COMPARE; - exp->CompareType = MLX_CMP_LESS; - exp->AggLevel = 1; - subexp = expAllocExpression(); - subexp->AggLevel = 1; - expAddNode(tree->AggExp, exp); - expAddNode(tree->AggExp, expLinkExpression(i0)); - expAddNode(tree->AggExp, subexp); - expAddNode(exp, expLinkExpression(i0)); - expAddNode(exp, expLinkExpression(subexp)); - } - - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) - { - if (tree->AggCount == 0) - { - tree->AggExp->Flags &= ~EXPR_F_NULL; - tree->DataType = i0->DataType; - tree->String = tree->Types.StringBuf; - tree->String[0] = '\0'; - tree->Alloc = 0; - tree->Integer = 0; - tree->Types.Double = 0; - tree->Types.Money.FractionPart = 0; - tree->Types.Money.WholePart = 0; - expCopyValue(i0,tree,0); - } - subexp = ((pExpression)(tree->AggExp->Children.Items[2])); - subexp->NodeType = expDataTypeToNodeType(i0->DataType); - expCopyValue(tree, subexp, 1); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - } - else - { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; + tree->DataType = DATA_T_INTEGER; + if (!i0) { + mssError(1, "EXP", "Parameter required for ascii() function."); + return -1; + } + if (i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "ascii() function takes a string parameter."); + return -1; + } + if (i0->String[0] == '\0') + tree->Flags |= EXPR_F_NULL; + + /** Parse first wide char **/ + bytesParsed = mbrtowc(&firstChar, i0->String, strlen(i0->String), NULL); + if (bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) { + goto errorInvalidUTF8Char; + } else + tree->Integer = firstChar; return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} + +int exp_fn_utf8_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + char* ptr; + size_t tmpLen; + + tree->DataType = DATA_T_INTEGER; + if (!i0 || !i1) { + mssError(1, "EXP", "Two string parameters required for charindex()"); + return -1; + } + if ((i0->Flags | i1->Flags) & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { + mssError(1, "EXP", "Two string parameters required for charindex()"); + return -1; + } + ptr = strstr(i1->String, i0->String); + if (ptr == NULL) + tree->Integer = 0; + else{ + tmpLen = mbstowcs(NULL, i1->String, ptr - i1->String) + 1; + if(tmpLen == (size_t)-1) + goto errorInvalidUTF8Char; + tree->Integer = tmpLen; } + return 0; +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} -int exp_fn_first(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) - { - if (tree->AggCount == 0) - { - expCopyValue(i0, tree, 1); - } - tree->AggCount++; - } - else - { - if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; +int exp_fn_utf8_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int i, oldStrLen, longStrLen, newStrLen; + + tree->DataType = DATA_T_STRING; + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for upper()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + oldStrLen = strlen(i0->String); + wchar_t longBuffer[oldStrLen + 1]; + longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + for (i = 0; i < oldStrLen + 1; i++) { + longBuffer[i] = towupper(longBuffer[i]); + } + newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); + if(newStrLen == (size_t)-1) + goto errorCharacterConversion; + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (newStrLen < 63) { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } else { + tree->String = (char*) nmSysMalloc(newStrLen + 1); + tree->Alloc = 1; + } + newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + +errorCharacterConversion: + mssError(1, "EXP", "Error converting characters"); + return -1; +} + +int exp_fn_utf8_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int i, oldStrLen, longStrLen, newStrLen; + + tree->DataType = DATA_T_STRING; + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for upper()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + oldStrLen = strlen(i0->String); + wchar_t longBuffer[oldStrLen + 1]; + longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + for (i = 0; i < oldStrLen + 1; i++) { + longBuffer[i] = towlower(longBuffer[i]); + } + newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); + if(newStrLen == (size_t)-1) + goto errorCharacterConversion; + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (newStrLen < 63) { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } else { + tree->String = (char*) nmSysMalloc(newStrLen + 1); + tree->Alloc = 1; } + newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + +errorCharacterConversion: + mssError(1, "EXP", "Error converting characters"); + return -1; +} + +int exp_fn_utf8_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + size_t wideLen; + tree->DataType = DATA_T_INTEGER; + if (i0 && i0->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for char_length()"); + return -1; + } + wideLen = mbstowcs(NULL, i0->String, strlen(i0->String) + 1); + if(wideLen == (size_t)-1) + goto errorInvalidUTF8Char; + tree->Integer = wideLen; + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} + +int exp_fn_utf8_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + int offsetFromEnd, currentPos = 0, numScanned = 0; + size_t charStrLen, longStrLen, step = 0; + mbstate_t currentState; + + memset(¤tState, 0, sizeof(currentState)); + + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "Invalid datatypes in right() function - takes (string,integer)"); + return -1; + } + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + } + charStrLen = strlen(i0->String); + longStrLen = mbstowcs(NULL, i0->String, charStrLen+1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + + offsetFromEnd = i1->Integer; + if (offsetFromEnd > longStrLen) offsetFromEnd = longStrLen; + if (offsetFromEnd < 0) offsetFromEnd = 0; + + while(numScanned < (longStrLen - offsetFromEnd)) { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + break; + numScanned++; + currentPos += step; + } -int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) - { - expCopyValue(i0, tree, 1); - tree->AggCount++; - } + tree->DataType = DATA_T_STRING; + tree->String = i0->String + currentPos; + tree->Alloc = 0; + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} + +int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + + size_t charStrLen, longStrLen, initial, len; + + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } + if (i2 && i2->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } + + /** Free any previous string in preparation for these results **/ + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); + tree->Alloc = 0; + } + tree->DataType = DATA_T_STRING; + + /** String lengths and character lengths and parameters **/ + initial = i0->Integer; + len = i2?i2->Integer:0; + charStrLen = strlen(i0->String); + longStrLen = mbstowcs(NULL, i0->String, charStrLen + 1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + + /** Check range of initial - shortcut if out of bounds **/ + if(initial > longStrLen) { + tree->Alloc = 0; + tree->String = i0->String + charStrLen; + return 0; + } + + /** Set length to length of string if too long **/ + if(initial + len - 1 > longStrLen || len <= 0) + len = longStrLen + 1 - initial; + + /** Shortcut for right, returning a pointer inside of the string **/ + if(initial + len - 1 >= longStrLen) { + /** Variables for right **/ + int currentPos = 0, step = 0, numScanned = 0; + mbstate_t currentState; + + /** Initialize current state **/ + memset(¤tState, 0, sizeof(currentState)); + + /** Scan over to the first char of the right substring to return **/ + while(numScanned < longStrLen - len) { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + break; + numScanned++; + currentPos += step; + } + + tree->Alloc = 0; + tree->String = i0->String + currentPos; + } + + /** Allocate a separate string and copy data **/ + else { + + /** Variables for substring in middle of string **/ + int currentPos = 0, step = 0, numScanned = 0, initialPos, i; + char * newStr; + mbstate_t currentState; + + memset(¤tState, 0, sizeof(currentState)); + + /** Scan to initial position of wanted substring **/ + while(numScanned < initial - 1) { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) { + tree->Alloc = 0; + tree->String = i0->String + charStrLen; + return 0; + } + numScanned++; + currentPos += step; + } + initialPos = currentPos; + + /** Scan to final position of wanted substring **/ + while(numScanned - initial < len - 1) { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + break; + numScanned++; + currentPos += step; + } + + /** Now initialPos is the first char and finalPos is one after last **/ + if(currentPos - initialPos > 63) { + tree->Alloc = 0; + newStr = tree->Types.StringBuf; + } + else { + tree->Alloc = 1; + newStr = nmSysMalloc(currentPos - initialPos + 1); + } + for(i = initialPos; i < currentPos; i++) { + newStr[i - initialPos] = i0->String[i]; + } + newStr[currentPos - initialPos] = '\0'; + tree->String = newStr; + } + + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} + +/*** Pad string expression i0 with integer expression i1 number of spaces ***/ +int exp_fn_utf8_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + size_t charStrLen, wideStrLen; + + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { + mssError(1, "EXP", "ralign() requires string parameter #1 and integer parameter #2"); + return -1; + } + tree->DataType = DATA_T_STRING; + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + + if (tree->Alloc && tree->String) nmSysFree(tree->String); + charStrLen = strlen(i0->String); + wideStrLen = mbstowcs(NULL, i0->String, charStrLen); + if(wideStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + if (wideStrLen >= i1->Integer) { + tree->Alloc = 0; + tree->String = i0->String; + } else - { - if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; + { + if (i1->Integer - wideStrLen + charStrLen >= 64) { + tree->Alloc = 1; + tree->String = (char*) nmSysMalloc(i1->Integer - wideStrLen + charStrLen + 1); + } else { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + sprintf(tree->String, "%*.*s", i1->Integer, i1->Integer, i0->String); + } return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} + +/** escape(string, escchars, badchars) **/ +int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + + /** Variables **/ + int escCharLen, badCharLen, numEscapees = 0, i, j, strLen, readPos, insertPos; + wchar_t current; + mbstate_t state; + char * output, * esc, * bad; + size_t charLen, badStrLen, escStrLen; + + tree->DataType = DATA_T_STRING; + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { + mssError(1, "EXP", "escape() requires two or three string parameters"); + return -1; } + if (i2 && i2->DataType != DATA_T_STRING) { + mssError(1, "EXP", "the optional third escape() parameter must be a string"); + bad = (i2->Flags & EXPR_F_NULL) ? "": i2->String; + return -1; + } + if ((i0->Flags & EXPR_F_NULL)) { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (i1->Flags & EXPR_F_NULL) + esc = ""; + else + esc = i1->String; + if (tree->Alloc && tree->String) nmSysFree(tree->String); + /** The esc and bad parameters in wchar_t form **/ + strLen = strlen(i0->String); + escCharLen = strlen(esc); + badCharLen = strlen(bad); + wchar_t escBuf[escCharLen + 2], badBuf[badCharLen + 1]; + escStrLen = mbstowcs(escBuf, esc, escCharLen + 1); + if(escStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + escBuf[escStrLen] = '\\'; + escBuf[++escStrLen] = '\0'; + badStrLen = mbstowcs(badBuf, bad, badCharLen + 1); + if(badStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + + /** Scan through to find all chars to escape **/ + memset(&state, '\0', sizeof(state)); + for(i = 0; i0->String[i] != '\0';) { + charLen = mbrtowc(¤t, i0->String + i, strLen - i, &state); + if(charLen == (size_t)-1 || charLen == (size_t)-2) { + goto errorInvalidUTF8Char; + } + i += charLen; + for(j = 0; j < badStrLen; j++) { + if(current == badBuf[j]){ + goto errorInvalidChar; + } + } + for(j = 0; j < escStrLen; j++) { + if(current == escBuf[j]) { + numEscapees++; + break; + } + } + } + if(numEscapees == 0) { + tree->Alloc = 0; + tree->String = i0->String; + return 0; + } -int -exp_internal_DefineFunctions() - { - - /** Function list for EXPR_N_FUNCTION nodes **/ - xhAdd(&EXP.Functions, "getdate", (char*)exp_fn_getdate); - xhAdd(&EXP.Functions, "user_name", (char*)exp_fn_user_name); - xhAdd(&EXP.Functions, "convert", (char*)exp_fn_convert); - xhAdd(&EXP.Functions, "wordify", (char*)exp_fn_wordify); - xhAdd(&EXP.Functions, "abs", (char*)exp_fn_abs); - xhAdd(&EXP.Functions, "ascii", (char*)exp_fn_ascii); - xhAdd(&EXP.Functions, "condition", (char*)exp_fn_condition); - xhAdd(&EXP.Functions, "charindex", (char*)exp_fn_charindex); - xhAdd(&EXP.Functions, "upper", (char*)exp_fn_upper); - xhAdd(&EXP.Functions, "lower", (char*)exp_fn_lower); - xhAdd(&EXP.Functions, "char_length", (char*)exp_fn_char_length); - xhAdd(&EXP.Functions, "datepart", (char*)exp_fn_datepart); - xhAdd(&EXP.Functions, "isnull", (char*)exp_fn_isnull); - xhAdd(&EXP.Functions, "ltrim", (char*)exp_fn_ltrim); - xhAdd(&EXP.Functions, "lztrim", (char*)exp_fn_lztrim); - xhAdd(&EXP.Functions, "rtrim", (char*)exp_fn_rtrim); - xhAdd(&EXP.Functions, "substring", (char*)exp_fn_substring); - xhAdd(&EXP.Functions, "right", (char*)exp_fn_right); - xhAdd(&EXP.Functions, "ralign", (char*)exp_fn_ralign); - xhAdd(&EXP.Functions, "replicate", (char*)exp_fn_replicate); - xhAdd(&EXP.Functions, "escape", (char*)exp_fn_escape); - xhAdd(&EXP.Functions, "quote", (char*)exp_fn_quote); - xhAdd(&EXP.Functions, "eval", (char*)exp_fn_eval); - xhAdd(&EXP.Functions, "round", (char*)exp_fn_round); - xhAdd(&EXP.Functions, "dateadd", (char*)exp_fn_dateadd); - xhAdd(&EXP.Functions, "truncate", (char*)exp_fn_truncate); - xhAdd(&EXP.Functions, "constrain", (char*)exp_fn_constrain); - xhAdd(&EXP.Functions, "sin", (char*)exp_fn_sin); - xhAdd(&EXP.Functions, "cos", (char*)exp_fn_cos); - xhAdd(&EXP.Functions, "tan", (char*)exp_fn_tan); - xhAdd(&EXP.Functions, "asin", (char*)exp_fn_asin); - xhAdd(&EXP.Functions, "acos", (char*)exp_fn_acos); - xhAdd(&EXP.Functions, "atan", (char*)exp_fn_atan); - xhAdd(&EXP.Functions, "atan2", (char*)exp_fn_atan2); - xhAdd(&EXP.Functions, "sqrt", (char*)exp_fn_sqrt); - xhAdd(&EXP.Functions, "square", (char*)exp_fn_square); - xhAdd(&EXP.Functions, "degrees", (char*)exp_fn_degrees); - xhAdd(&EXP.Functions, "radians", (char*)exp_fn_radians); - - xhAdd(&EXP.Functions, "count", (char*)exp_fn_count); - xhAdd(&EXP.Functions, "avg", (char*)exp_fn_avg); - xhAdd(&EXP.Functions, "sum", (char*)exp_fn_sum); - xhAdd(&EXP.Functions, "max", (char*)exp_fn_max); - xhAdd(&EXP.Functions, "min", (char*)exp_fn_min); - xhAdd(&EXP.Functions, "first", (char*)exp_fn_first); - xhAdd(&EXP.Functions, "last", (char*)exp_fn_last); - - /** Reverse functions **/ - xhAdd(&EXP.ReverseFunctions, "isnull", (char*)exp_fn_reverse_isnull); + memset(&state, '\0', sizeof(state)); + if(numEscapees + strLen <= 63){ + output = tree->Types.StringBuf; + tree->Alloc = 0; + } + else{ + output = nmSysMalloc(numEscapees + strLen + 1); + tree->Alloc = 1; + } + for(readPos = 0, insertPos = 0; readPos < strLen;) { + charLen = mbrtowc(¤t, i0->String + readPos, strLen - readPos, &state); + for(j = 0; j < escStrLen; j++) { + if(current == escBuf[j]) { + output[insertPos] = '\\'; + insertPos++; + break; + } + } + while(charLen--) { + output[insertPos++] = i0->String[readPos++]; + } + } + output[numEscapees + strLen] = '\0'; + tree->String = output; return 0; + + /** Different types of errors **/ +errorInvalidChar: + mssError(1, "EXP", "WARNING!! String contains invalid character asc=%d", (int) (current)); + return -1; +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; +} + +int +exp_internal_DefineFunctions() { + + /** Function list for EXPR_N_FUNCTION nodes **/ + xhAdd(&EXP.Functions, "getdate", (char*) exp_fn_getdate); + xhAdd(&EXP.Functions, "user_name", (char*) exp_fn_user_name); + xhAdd(&EXP.Functions, "convert", (char*) exp_fn_convert); + xhAdd(&EXP.Functions, "wordify", (char*) exp_fn_wordify); + xhAdd(&EXP.Functions, "abs", (char*) exp_fn_abs); + xhAdd(&EXP.Functions, "condition", (char*) exp_fn_condition); + xhAdd(&EXP.Functions, "datepart", (char*) exp_fn_datepart); + xhAdd(&EXP.Functions, "isnull", (char*) exp_fn_isnull); + xhAdd(&EXP.Functions, "ltrim", (char*) exp_fn_ltrim); + xhAdd(&EXP.Functions, "lztrim", (char*) exp_fn_lztrim); + xhAdd(&EXP.Functions, "rtrim", (char*) exp_fn_rtrim); + xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); + xhAdd(&EXP.Functions, "replicate", (char*) exp_fn_replicate); + xhAdd(&EXP.Functions, "quote", (char*) exp_fn_quote); + xhAdd(&EXP.Functions, "eval", (char*) exp_fn_eval); + xhAdd(&EXP.Functions, "round", (char*) exp_fn_round); + xhAdd(&EXP.Functions, "dateadd", (char*) exp_fn_dateadd); + xhAdd(&EXP.Functions, "truncate", (char*) exp_fn_truncate); + xhAdd(&EXP.Functions, "constrain", (char*) exp_fn_constrain); + xhAdd(&EXP.Functions, "sin", (char*) exp_fn_sin); + xhAdd(&EXP.Functions, "cos", (char*) exp_fn_cos); + xhAdd(&EXP.Functions, "tan", (char*) exp_fn_tan); + xhAdd(&EXP.Functions, "asin", (char*) exp_fn_asin); + xhAdd(&EXP.Functions, "acos", (char*) exp_fn_acos); + xhAdd(&EXP.Functions, "atan", (char*) exp_fn_atan); + xhAdd(&EXP.Functions, "atan2", (char*) exp_fn_atan2); + xhAdd(&EXP.Functions, "sqrt", (char*) exp_fn_sqrt); + xhAdd(&EXP.Functions, "square", (char*) exp_fn_square); + xhAdd(&EXP.Functions, "degrees", (char*) exp_fn_degrees); + xhAdd(&EXP.Functions, "radians", (char*) exp_fn_radians); + + xhAdd(&EXP.Functions, "count", (char*) exp_fn_count); + xhAdd(&EXP.Functions, "avg", (char*) exp_fn_avg); + xhAdd(&EXP.Functions, "sum", (char*) exp_fn_sum); + xhAdd(&EXP.Functions, "max", (char*) exp_fn_max); + xhAdd(&EXP.Functions, "min", (char*) exp_fn_min); + xhAdd(&EXP.Functions, "first", (char*) exp_fn_first); + xhAdd(&EXP.Functions, "last", (char*) exp_fn_last); + + /** Reverse functions **/ + xhAdd(&EXP.ReverseFunctions, "isnull", (char*) exp_fn_reverse_isnull); + + /** UTF-8/ASCII dependent **/ + if (CxGlobals.CharacterMode == CharModeSigleByte) { + xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_ascii); + xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_charindex); + xhAdd(&EXP.Functions, "upper", (char*) exp_fn_upper); + xhAdd(&EXP.Functions, "lower", (char*) exp_fn_lower); + xhAdd(&EXP.Functions, "char_length", (char*) exp_fn_char_length); + xhAdd(&EXP.Functions, "right", (char*) exp_fn_right); + xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_ralign); + xhAdd(&EXP.Functions, "escape", (char*) exp_fn_escape); + } else { + xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_utf8_ascii); + xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_utf8_charindex); + xhAdd(&EXP.Functions, "upper", (char*) exp_fn_utf8_upper); + xhAdd(&EXP.Functions, "lower", (char*) exp_fn_utf8_lower); + xhAdd(&EXP.Functions, "char_length", (char*) exp_fn_utf8_char_length); + xhAdd(&EXP.Functions, "right", (char*) exp_fn_utf8_right); + xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); + xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); } + + return 0; +} diff --git a/centrallix/include/centrallix.h b/centrallix/include/centrallix.h index c86dbe809..7c141dbe4 100644 --- a/centrallix/include/centrallix.h +++ b/centrallix/include/centrallix.h @@ -2,7 +2,7 @@ #define _CENTRALLIX_H #include "stparse.h" - +#include "stparse_ne.h" /*** Platform-independent types definition ***/ typedef long long CXINT64; @@ -18,6 +18,11 @@ typedef char CXCHAR; #define CX_CONV32(x) ((CX_CONV16((x)&0xffff)<<16)|CX_CONV16(((x)>>16)&0xffff)) #define CX_CONV64(x) ((CX_CONV32((x)&0xffffffffLL)<<32)|CX_CONV32(((x)>>32)&0xffffffffLL)) +/** Different types of character modes that Centrallix supports. **/ +typedef enum{ + CharModeUTF8, /*** For when the locale supports UTF-8 **/ + CharModeSigleByte /** For when the locale is using a single byte encoding. **/ +} CharMode; /*** Loaded module info ***/ typedef struct _CXM @@ -51,6 +56,9 @@ typedef struct _CXG pCxModule ModuleList; XArray ShutdownHandlers; int Flags; + CharMode CharacterMode; /* This and down deal with charsets */ + pStruct CharsetMap; /* This is the contents of the charset.cfg file */ + /* for looking up equivalent character sets. */ } CxGlobals_t, *pCxGlobals_t; From ee43333b1de19e0f00ac8d046ddfd68d72d6251c Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Tue, 28 Jun 2011 16:53:13 -0400 Subject: [PATCH 002/124] Fixed exp_functions.c Re-added the UTF-8 functions to a rolled-back version of exp_functions.c to get proper code format and get rid of complete refactoring of code. --- centrallix/expression/exp_functions.c | 3480 ++++++++++++------------- 1 file changed, 1639 insertions(+), 1841 deletions(-) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 1c3e87ee0..af5d247e0 100644 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include "obj.h" #include "cxlib/mtask.h" #include "cxlib/xarray.h" @@ -15,7 +13,6 @@ #include "cxlib/mtlexer.h" #include "expression.h" #include "cxlib/mtsession.h" -#include "centrallix.h" /************************************************************************/ /* Centrallix Application Server System */ @@ -196,943 +193,1139 @@ /****** Evaluator functions follow for expEvalFunction ******/ -int exp_fn_getdate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_getdate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { tree->DataType = DATA_T_DATETIME; objCurrentDate(&(tree->Types.Date)); return 0; -} + } -int exp_fn_user_name(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_user_name(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; tree->DataType = DATA_T_STRING; ptr = mssUserName(); - if (!ptr) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!ptr) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } tree->String = tree->Types.StringBuf; memccpy(tree->String, ptr, 0, 63); tree->String[63] = '\0'; return 0; -} + } -int exp_fn_convert(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_convert(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { void* vptr; char* ptr; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i0->Flags & EXPR_F_NULL)) { - mssError(1, "EXP", "convert() requires data type and value to be converted"); - return -1; - } - switch (i1->DataType) { - case DATA_T_INTEGER: vptr = &(i1->Integer); - break; - case DATA_T_STRING: vptr = i1->String; - break; - case DATA_T_DOUBLE: vptr = &(i1->Types.Double); - break; - case DATA_T_DATETIME: vptr = &(i1->Types.Date); - break; - case DATA_T_MONEY: vptr = &(i1->Types.Money); - break; - default: - mssError(1, "EXP", "convert(): unsupported arg 2 datatype"); - return -1; - } - if (!strcmp(i0->String, "integer")) { - tree->DataType = DATA_T_INTEGER; - if (i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - tree->Integer = objDataToInteger(i1->DataType, vptr, NULL); - } else if (!strcmp(i0->String, "string")) { - tree->DataType = DATA_T_STRING; - if (i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - ptr = objDataToStringTmp(i1->DataType, vptr, 0); - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } - if (strlen(ptr) > 63) { - tree->Alloc = 1; - tree->String = nmSysStrdup(ptr); - } else { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - strcpy(tree->String, ptr); - } - } else if (!strcmp(i0->String, "double")) { - tree->DataType = DATA_T_DOUBLE; - if (i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - tree->Types.Double = objDataToDouble(i1->DataType, vptr); - } else if (!strcmp(i0->String, "money")) { - tree->DataType = DATA_T_MONEY; - if (i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - objDataToMoney(i1->DataType, vptr, &(tree->Types.Money)); - } else if (!strcmp(i0->String, "datetime")) { - tree->DataType = DATA_T_DATETIME; - if (i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - objDataToDateTime(i1->DataType, vptr, &(tree->Types.Date), NULL); - } else { - mssError(1, "EXP", "convert() datatype '%s' is invalid", i0->String); - } + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i0->Flags & EXPR_F_NULL)) + { + mssError(1,"EXP","convert() requires data type and value to be converted"); + return -1; + } + switch(i1->DataType) + { + case DATA_T_INTEGER: vptr = &(i1->Integer); break; + case DATA_T_STRING: vptr = i1->String; break; + case DATA_T_DOUBLE: vptr = &(i1->Types.Double); break; + case DATA_T_DATETIME: vptr = &(i1->Types.Date); break; + case DATA_T_MONEY: vptr = &(i1->Types.Money); break; + default: + mssError(1,"EXP","convert(): unsupported arg 2 datatype"); + return -1; + } + if (!strcmp(i0->String,"integer")) + { + tree->DataType = DATA_T_INTEGER; + if (i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + tree->Integer = objDataToInteger(i1->DataType, vptr, NULL); + } + else if (!strcmp(i0->String,"string")) + { + tree->DataType = DATA_T_STRING; + if (i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + ptr = objDataToStringTmp(i1->DataType, vptr, 0); + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } + if (strlen(ptr) > 63) + { + tree->Alloc = 1; + tree->String = nmSysStrdup(ptr); + } + else + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + strcpy(tree->String, ptr); + } + } + else if (!strcmp(i0->String,"double")) + { + tree->DataType = DATA_T_DOUBLE; + if (i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + tree->Types.Double = objDataToDouble(i1->DataType, vptr); + } + else if (!strcmp(i0->String,"money")) + { + tree->DataType = DATA_T_MONEY; + if (i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + objDataToMoney(i1->DataType, vptr, &(tree->Types.Money)); + } + else if (!strcmp(i0->String,"datetime")) + { + tree->DataType = DATA_T_DATETIME; + if (i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + objDataToDateTime(i1->DataType, vptr, &(tree->Types.Date), NULL); + } + else + { + mssError(1,"EXP","convert() datatype '%s' is invalid", i0->String); + } return 0; -} + } -int exp_fn_wordify(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_wordify(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; tree->DataType = DATA_T_STRING; - if (!i0) { - mssError(1, "EXP", "Parameter required for wordify() function."); - return -1; - } - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - switch (i0->DataType) { - case DATA_T_INTEGER: - ptr = objDataToWords(DATA_T_INTEGER, &(i0->Integer)); - break; - - case DATA_T_MONEY: - ptr = objDataToWords(DATA_T_MONEY, &(i0->Types.Money)); - break; - - default: - mssError(1, "EXP", "Can only convert integer and money types with wordify()"); - return -1; - } - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } - if (strlen(ptr) > 63) { - tree->String = nmSysStrdup(ptr); - tree->Alloc = 1; - } else { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; + if (!i0) + { + mssError(1,"EXP","Parameter required for wordify() function."); + return -1; + } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + switch(i0->DataType) + { + case DATA_T_INTEGER: + ptr = objDataToWords(DATA_T_INTEGER, &(i0->Integer)); + break; + + case DATA_T_MONEY: + ptr = objDataToWords(DATA_T_MONEY, &(i0->Types.Money)); + break; + + default: + mssError(1,"EXP","Can only convert integer and money types with wordify()"); + return -1; + } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } + if (strlen(ptr) > 63) + { + tree->String = nmSysStrdup(ptr); + tree->Alloc = 1; + } + else + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; strcpy(tree->String, ptr); - } + } return 0; -} - -int exp_fn_abs(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!i0) { - mssError(1, "EXP", "Parameter required for abs() function."); - return -1; } + + +int exp_fn_abs(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!i0) + { + mssError(1,"EXP","Parameter required for abs() function."); + return -1; + } tree->DataType = i0->DataType; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - } else { - switch (i0->DataType) { - case DATA_T_INTEGER: - tree->Integer = abs(i0->Integer); - break; - - case DATA_T_DOUBLE: - tree->Types.Double = fabs(i0->Types.Double); - break; - - case DATA_T_MONEY: - if (i0->Types.Money.WholePart >= 0) { - tree->Types.Money.WholePart = i0->Types.Money.WholePart; - tree->Types.Money.FractionPart = i0->Types.Money.FractionPart; - } else { - if (i0->Types.Money.FractionPart != 0) { - tree->Types.Money.WholePart = -(i0->Types.Money.WholePart + 1); - tree->Types.Money.FractionPart = 10000 - i0->Types.Money.FractionPart; - } else { - tree->Types.Money.WholePart = -i0->Types.Money.WholePart; - tree->Types.Money.FractionPart = 0; - } - } - break; - - default: - mssError(1, "EXP", "Invalid data type for abs() function"); - return -1; - } - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + } + else + { + switch(i0->DataType) + { + case DATA_T_INTEGER: + tree->Integer = abs(i0->Integer); + break; + + case DATA_T_DOUBLE: + tree->Types.Double = fabs(i0->Types.Double); + break; + + case DATA_T_MONEY: + if (i0->Types.Money.WholePart >= 0) + { + tree->Types.Money.WholePart = i0->Types.Money.WholePart; + tree->Types.Money.FractionPart = i0->Types.Money.FractionPart; + } + else + { + if (i0->Types.Money.FractionPart != 0) + { + tree->Types.Money.WholePart = -(i0->Types.Money.WholePart + 1); + tree->Types.Money.FractionPart = 10000 - i0->Types.Money.FractionPart; + } + else + { + tree->Types.Money.WholePart = -i0->Types.Money.WholePart; + tree->Types.Money.FractionPart = 0; + } + } + break; + + default: + mssError(1,"EXP","Invalid data type for abs() function"); + return -1; + } + } return 0; -} + } + -int exp_fn_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { tree->DataType = DATA_T_INTEGER; - if (!i0) { - mssError(1, "EXP", "Parameter required for ascii() function."); - return -1; - } - if (i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "ascii() function takes a string parameter."); - return -1; - } + if (!i0) + { + mssError(1,"EXP","Parameter required for ascii() function."); + return -1; + } + if (i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","ascii() function takes a string parameter."); + return -1; + } if (i0->String[0] == '\0') - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; else - tree->Integer = i0->String[0]; + tree->Integer = i0->String[0]; return 0; -} - -int exp_fn_condition(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!i0 || !i1 || !i2) { - mssError(1, "EXP", "Three parameters required for condition()"); - return -1; - } - if (exp_internal_EvalTree(i0, objlist) < 0) { - return -1; - } - if (i0->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "condition() first parameter must evaluate to boolean"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) { - tree->DataType = DATA_T_INTEGER; - tree->Flags |= EXPR_F_NULL; - i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); - i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); - return 0; - } - if (i0->Integer != 0) { - /** True, return 2nd argument i1 **/ - i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); - if (exp_internal_EvalTree(i1, objlist) < 0) { - return -1; - } - if (i2->AggLevel > 0) - if (exp_internal_EvalTree(i2, objlist) < 0) - return -1; - tree->DataType = i1->DataType; - if (i1->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - switch (i1->DataType) { - case DATA_T_INTEGER: tree->Integer = i1->Integer; - break; - case DATA_T_STRING: tree->String = i1->String; - tree->Alloc = 0; - break; - default: memcpy(&(tree->Types), &(i1->Types), sizeof (tree->Types)); - break; - } - } else { - /** False, return 3rd argument i2 **/ - if (i1->AggLevel > 0) { - if (exp_internal_EvalTree(i1, objlist) < 0) - return -1; - } else { - i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); - } - if (exp_internal_EvalTree(i2, objlist) < 0) { - return -1; - } - tree->DataType = i2->DataType; - if (i2->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - switch (i2->DataType) { - case DATA_T_INTEGER: tree->Integer = i2->Integer; - break; - case DATA_T_STRING: tree->String = i2->String; - tree->Alloc = 0; - break; - default: memcpy(&(tree->Types), &(i2->Types), sizeof (tree->Types)); - break; - } } + +int exp_fn_condition(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!i0 || !i1 || !i2) + { + mssError(1,"EXP","Three parameters required for condition()"); + return -1; + } + if (exp_internal_EvalTree(i0,objlist) < 0) + { + return -1; + } + if (i0->DataType != DATA_T_INTEGER) + { + mssError(1,"EXP","condition() first parameter must evaluate to boolean"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) + { + tree->DataType = DATA_T_INTEGER; + tree->Flags |= EXPR_F_NULL; + i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); + i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); + return 0; + } + if (i0->Integer != 0) + { + /** True, return 2nd argument i1 **/ + i2->ObjDelayChangeMask |= (objlist->ModCoverageMask & i2->ObjCoverageMask); + if (exp_internal_EvalTree(i1,objlist) < 0) + { + return -1; + } + if (i2->AggLevel > 0) + if (exp_internal_EvalTree(i2,objlist) < 0) + return -1; + tree->DataType = i1->DataType; + if (i1->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + switch(i1->DataType) + { + case DATA_T_INTEGER: tree->Integer = i1->Integer; break; + case DATA_T_STRING: tree->String = i1->String; tree->Alloc = 0; break; + default: memcpy(&(tree->Types), &(i1->Types), sizeof(tree->Types)); break; + } + } + else + { + /** False, return 3rd argument i2 **/ + if (i1->AggLevel > 0) + { + if (exp_internal_EvalTree(i1,objlist) < 0) + return -1; + } + else + { + i1->ObjDelayChangeMask |= (objlist->ModCoverageMask & i1->ObjCoverageMask); + } + if (exp_internal_EvalTree(i2,objlist) < 0) + { + return -1; + } + tree->DataType = i2->DataType; + if (i2->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + switch(i2->DataType) + { + case DATA_T_INTEGER: tree->Integer = i2->Integer; break; + case DATA_T_STRING: tree->String = i2->String; tree->Alloc = 0; break; + default: memcpy(&(tree->Types), &(i2->Types), sizeof(tree->Types)); break; + } + } return 0; -} + } -int exp_fn_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; tree->DataType = DATA_T_INTEGER; - if (!i0 || !i1) { - mssError(1, "EXP", "Two string parameters required for charindex()"); - return -1; - } - if ((i0->Flags | i1->Flags) & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { - mssError(1, "EXP", "Two string parameters required for charindex()"); - return -1; - } + if (!i0 || !i1) + { + mssError(1,"EXP","Two string parameters required for charindex()"); + return -1; + } + if ((i0->Flags | i1->Flags) & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) + { + mssError(1,"EXP","Two string parameters required for charindex()"); + return -1; + } ptr = strstr(i1->String, i0->String); if (ptr == NULL) - tree->Integer = 0; + tree->Integer = 0; else tree->Integer = (ptr - i1->String) + 1; return 0; -} + } + -int exp_fn_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int n, i; +int exp_fn_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int n,i; tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for upper()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","One string parameter required for upper()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } n = strlen(i0->String); - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (n < 63) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } else { - tree->String = (char*) nmSysMalloc(n + 1); - tree->Alloc = 1; - } - for (i = 0; i < n + 1; i++) { - if (i0->String[i] >= 'a' && i0->String[i] <= 'z') tree->String[i] = i0->String[i] - 32; - else tree->String[i] = i0->String[i]; - } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (n < 63) + { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } + else + { + tree->String = (char*)nmSysMalloc(n+1); + tree->Alloc = 1; + } + for(i=0;iString[i] >= 'a' && i0->String[i] <= 'z') tree->String[i] = i0->String[i] - 32; + else tree->String[i] = i0->String[i]; + } return 0; -} + } -int exp_fn_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int n, i; + +int exp_fn_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int n,i; tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for lower()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","One string parameter required for lower()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } n = strlen(i0->String); - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (n < 63) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } else { - tree->String = (char*) nmSysMalloc(n + 1); - tree->Alloc = 1; - } - for (i = 0; i < n + 1; i++) { - if (i0->String[i] >= 'A' && i0->String[i] <= 'Z') tree->String[i] = i0->String[i] + 32; - else tree->String[i] = i0->String[i]; - } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (n < 63) + { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } + else + { + tree->String = (char*)nmSysMalloc(n+1); + tree->Alloc = 1; + } + for(i=0;iString[i] >= 'A' && i0->String[i] <= 'Z') tree->String[i] = i0->String[i] + 32; + else tree->String[i] = i0->String[i]; + } return 0; -} + } -int exp_fn_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { tree->DataType = DATA_T_INTEGER; - if (i0 && i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for char_length()"); - return -1; - } + if (i0 && i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","One string parameter required for char_length()"); + return -1; + } tree->Integer = strlen(i0->String); return 0; -} + } + -int exp_fn_datepart(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_datepart(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { pDateTime dtptr; DateTime dt; tree->DataType = DATA_T_INTEGER; - if (i0 && i1 && ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL))) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || !i1) { - mssError(1, "EXP", "datepart() requires two parameters"); - return -1; - } - if (i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "param 1 to datepart() must be month, day, year, hour, minute, or second"); - return -1; - } - if (i1->DataType == DATA_T_DATETIME) { - dtptr = &(i1->Types.Date); - } else if (i1->DataType == DATA_T_STRING) { - if (objDataToDateTime(DATA_T_STRING, i1->String, &dt, NULL) < 0) { - mssError(1, "EXP", "in datepart(), failed to parse string date/time value"); - return -1; - } - dtptr = &dt; - } else { - mssError(1, "EXP", "param 2 to datepart() must be a date/time value"); - return -1; - } - if (!strcasecmp(i0->String, "year")) - tree->Integer = dtptr->Part.Year + 1900; - else if (!strcasecmp(i0->String, "month")) + if (i0 && i1 && ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL))) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || !i1) + { + mssError(1,"EXP","datepart() requires two parameters"); + return -1; + } + if (i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","param 1 to datepart() must be month, day, year, hour, minute, or second"); + return -1; + } + if (i1->DataType == DATA_T_DATETIME) + { + dtptr = &(i1->Types.Date); + } + else if (i1->DataType == DATA_T_STRING) + { + if (objDataToDateTime(DATA_T_STRING, i1->String, &dt, NULL) < 0) + { + mssError(1,"EXP","in datepart(), failed to parse string date/time value"); + return -1; + } + dtptr = &dt; + } + else + { + mssError(1,"EXP","param 2 to datepart() must be a date/time value"); + return -1; + } + if (!strcasecmp(i0->String,"year")) + tree->Integer = dtptr->Part.Year + 1900; + else if (!strcasecmp(i0->String,"month")) tree->Integer = dtptr->Part.Month + 1; - else if (!strcasecmp(i0->String, "day")) + else if (!strcasecmp(i0->String,"day")) tree->Integer = dtptr->Part.Day + 1; - else if (!strcasecmp(i0->String, "hour")) + else if (!strcasecmp(i0->String,"hour")) tree->Integer = dtptr->Part.Hour; - else if (!strcasecmp(i0->String, "minute")) + else if (!strcasecmp(i0->String,"minute")) tree->Integer = dtptr->Part.Minute; - else if (!strcasecmp(i0->String, "second")) + else if (!strcasecmp(i0->String,"second")) tree->Integer = dtptr->Part.Second; - else { - mssError(1, "EXP", "param 1 to datepart() must be month, day, year, hour, minute, or second"); - return -1; - } + else + { + mssError(1,"EXP","param 1 to datepart() must be month, day, year, hour, minute, or second"); + return -1; + } return 0; -} + } // Reverse isnull() just passes the value on to the first parameter, so the // isnull() function can be used to set default values on SQL query properties. - -int exp_fn_reverse_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!i0) { - mssError(1, "EXP", "isnull() requires two parameters"); - return -1; - } - if (tree->Flags & EXPR_F_NULL) - i0->Flags |= EXPR_F_NULL; +int exp_fn_reverse_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!i0) + { + mssError(1,"EXP","isnull() requires two parameters"); + return -1; + } + if (tree->Flags & EXPR_F_NULL) + i0->Flags |= EXPR_F_NULL; else - i0->Flags &= ~EXPR_F_NULL; - switch (tree->DataType) { - case DATA_T_INTEGER: i0->Integer = tree->Integer; - break; - case DATA_T_STRING: - if (i0->Alloc && i0->String) { - nmSysFree(i0->String); - } - i0->Alloc = 0; - i0->String = tree->String; - break; - default: memcpy(&(i0->Types), &(tree->Types), sizeof (tree->Types)); - break; - } + i0->Flags &= ~EXPR_F_NULL; + switch(tree->DataType) + { + case DATA_T_INTEGER: i0->Integer = tree->Integer; break; + case DATA_T_STRING: + if (i0->Alloc && i0->String) + { + nmSysFree(i0->String); + } + i0->Alloc = 0; + i0->String = tree->String; + break; + default: memcpy(&(i0->Types), &(tree->Types), sizeof(tree->Types)); break; + } i0->DataType = tree->DataType; return expReverseEvalTree(i0, objlist); -} - -int exp_fn_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!i0 || !i1) { - mssError(1, "EXP", "isnull() requires two parameters"); - return -1; } + +int exp_fn_isnull(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!i0 || !i1) + { + mssError(1,"EXP","isnull() requires two parameters"); + return -1; + } if (i0->Flags & EXPR_F_NULL) i0 = i1; tree->DataType = i0->DataType; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - switch (i0->DataType) { - case DATA_T_INTEGER: tree->Integer = i0->Integer; - break; - case DATA_T_STRING: tree->String = i0->String; - tree->Alloc = 0; - break; - default: memcpy(&(tree->Types), &(i0->Types), sizeof (tree->Types)); - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + switch(i0->DataType) + { + case DATA_T_INTEGER: tree->Integer = i0->Integer; break; + case DATA_T_STRING: tree->String = i0->String; tree->Alloc = 0; break; + default: memcpy(&(tree->Types), &(i0->Types), sizeof(tree->Types)); + } return 0; -} + } -int exp_fn_replicate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int nl, n, l; +int exp_fn_replicate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int nl,n,l; char* ptr; int i; - - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) { - mssError(1, "EXP", "replicate() requires a string and a numeric parameter"); - return -1; - } - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL) || (i1->DataType == DATA_T_INTEGER && i1->Integer < 0) || (i1->DataType == DATA_T_DOUBLE && i1->Types.Double < 0)) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } + + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) + { + mssError(1,"EXP","replicate() requires a string and a numeric parameter"); + return -1; + } + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL) || (i1->DataType == DATA_T_INTEGER && i1->Integer < 0) || (i1->DataType == DATA_T_DOUBLE && i1->Types.Double < 0)) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } tree->DataType = DATA_T_STRING; - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } tree->Alloc = 0; - if (i1->DataType == DATA_T_INTEGER) { - n = (i1->Integer > 255) ? 255 : i1->Integer; - } else { - n = i1->Types.Double + 0.0001; - n = (n > 255) ? 255 : n; - } - nl = strlen(i0->String) * n; - if (nl <= 63) { - tree->String = tree->Types.StringBuf; - } else { - tree->Alloc = 1; - tree->String = nmSysMalloc(nl + 1); - } + if (i1->DataType == DATA_T_INTEGER) + { + n = (i1->Integer > 255)?255:i1->Integer; + } + else + { + n = i1->Types.Double + 0.0001; + n = (n > 255)?255:n; + } + nl = strlen(i0->String)*n; + if (nl <= 63) + { + tree->String = tree->Types.StringBuf; + } + else + { + tree->Alloc = 1; + tree->String = nmSysMalloc(nl+1); + } ptr = tree->String; l = strlen(i0->String); ptr[0] = '\0'; - if (l) for (i = 0; i < n; i++) { - strcpy(ptr, i0->String); - ptr += l; - } + if (l) for(i=0;iString); + ptr += l; + } return 0; -} + } -int exp_fn_lztrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_lztrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; - if (!i0 || i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "lztrim() only works on STRING data types"); - return -1; - } - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } + if (!i0 || i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","lztrim() only works on STRING data types"); + return -1; + } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } tree->DataType = DATA_T_STRING; ptr = i0->String; - while (*ptr == '0' && (ptr[1] >= '0' && ptr[1] <= '9')) ptr++; + while(*ptr == '0' && (ptr[1] >= '0' && ptr[1] <= '9')) ptr++; tree->String = ptr; tree->Alloc = 0; return 0; -} + } -int exp_fn_ltrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_ltrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; - if (!i0 || i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "ltrim() only works on STRING data types"); - return -1; - } - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } + if (!i0 || i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","ltrim() only works on STRING data types"); + return -1; + } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } tree->DataType = DATA_T_STRING; ptr = i0->String; - while (*ptr == ' ') ptr++; + while(*ptr == ' ') ptr++; tree->String = ptr; tree->Alloc = 0; return 0; -} + } -int exp_fn_rtrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_rtrim(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; int n; - if (!i0 || i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "rtrim() only works on STRING data types"); - return -1; - } - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } + if (!i0 || i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","rtrim() only works on STRING data types"); + return -1; + } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } tree->Alloc = 0; tree->DataType = DATA_T_STRING; ptr = i0->String + strlen(i0->String); - while (ptr > i0->String && ptr[-1] == ' ') ptr--; - if (ptr == i0->String + strlen(i0->String)) { - /** optimization for strings are still the same **/ - tree->String = i0->String; - } else { - /** have to copy because we removed spaces **/ - n = ptr - i0->String; - if (n < 63) { - tree->String = tree->Types.StringBuf; - memcpy(tree->String, i0->String, n); - tree->String[n] = '\0'; - tree->Alloc = 0; - } else { - tree->String = (char*) nmSysMalloc(n + 1); - memcpy(tree->String, i0->String, n); - tree->String[n] = '\0'; - tree->Alloc = 1; - } - } + while(ptr > i0->String && ptr[-1] == ' ') ptr--; + if (ptr == i0->String + strlen(i0->String)) + { + /** optimization for strings are still the same **/ + tree->String = i0->String; + } + else + { + /** have to copy because we removed spaces **/ + n = ptr - i0->String; + if (n < 63) + { + tree->String = tree->Types.StringBuf; + memcpy(tree->String, i0->String, n); + tree->String[n] = '\0'; + tree->Alloc = 0; + } + else + { + tree->String = (char*)nmSysMalloc(n+1); + memcpy(tree->String, i0->String, n); + tree->String[n] = '\0'; + tree->Alloc = 1; + } + } return 0; -} + } -int exp_fn_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int n, i; - if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "Invalid datatypes in right() function - takes (string,integer)"); - return -1; - } - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } +int exp_fn_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int n,i; + + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) + { + mssError(1,"EXP","Invalid datatypes in right() function - takes (string,integer)"); + return -1; + } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } n = strlen(i0->String); i = i1->Integer; - if (i > n) i = n; + if (i>n) i = n; if (i < 0) i = 0; tree->DataType = DATA_T_STRING; tree->String = i0->String + (n - i); tree->Alloc = 0; return 0; -} + } + -int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int i, n; +int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int i,n; char* ptr; - if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); - return -1; - } - if (i2 && i2->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); - return -1; - } + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) + { + mssError(1,"EXP","Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } + if (i2 && i2->DataType != DATA_T_INTEGER) + { + mssError(1,"EXP","Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } n = strlen(i0->String); - i = i1->Integer - 1; - if (i < 0) i = 0; + i = i1->Integer-1; + if (i<0) i = 0; if (i > n) i = n; ptr = i0->String + i; - i = i2 ? (i2->Integer) : (strlen(ptr)); + i = i2?(i2->Integer):(strlen(ptr)); if (i < 0) i = 0; if (i > strlen(ptr)) i = strlen(ptr); /** Ok, got position and length. Now make new string in tree-> **/ - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (i < 64) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } else { - tree->String = (char*) nmSysMalloc(i + 1); - tree->Alloc = 1; - } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (i<64) + { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } + else + { + tree->String = (char*)nmSysMalloc(i+1); + tree->Alloc = 1; + } memcpy(tree->String, ptr, i); tree->String[i] = '\0'; tree->DataType = DATA_T_STRING; return 0; -} + } + /*** Pad string expression i0 with integer expression i1 number of spaces ***/ -int exp_fn_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { int n; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "ralign() requires string parameter #1 and integer parameter #2"); - return -1; - } + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) + { + mssError(1,"EXP","ralign() requires string parameter #1 and integer parameter #2"); + return -1; + } tree->DataType = DATA_T_STRING; - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } n = strlen(i0->String); if (tree->Alloc && tree->String) nmSysFree(tree->String); - if (n >= i1->Integer) { - tree->Alloc = 0; - tree->String = i0->String; - } else { - if (i1->Integer >= 64) { - tree->Alloc = 1; - tree->String = (char*) nmSysMalloc(i1->Integer + 1); - } else { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } - sprintf(tree->String, "%*.*s", i1->Integer, i1->Integer, i0->String); - } + if (n >= i1->Integer) + { + tree->Alloc = 0; + tree->String = i0->String; + } + else + { + if (i1->Integer>=64) + { + tree->Alloc = 1; + tree->String = (char*)nmSysMalloc(i1->Integer+1); + } + else + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + sprintf(tree->String,"%*.*s",i1->Integer,i1->Integer,i0->String); + } return 0; -} + } + /** escape(string, escchars, badchars) **/ -int exp_fn_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { char* ptr; char* dst; char* escchars; - int esccnt, len; + int esccnt,len; tree->DataType = DATA_T_STRING; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { - mssError(1, "EXP", "escape() requires two or three string parameters"); - return -1; - } - if (i2 && i2->DataType != DATA_T_STRING) { - mssError(1, "EXP", "the optional third escape() parameter must be a string"); - return -1; - } - if (i2 && !(i2->Flags & EXPR_F_NULL) && (ptr = strpbrk(i0->String, i2->String)) != NULL) { - mssError(1, "EXP", "WARNING!! String contains invalid character asc=%d", (int) (*ptr)); - return -1; - } - if ((i0->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) + { + mssError(1,"EXP","escape() requires two or three string parameters"); + return -1; + } + if (i2 && i2->DataType != DATA_T_STRING) + { + mssError(1,"EXP","the optional third escape() parameter must be a string"); + return -1; + } + if (i2 && !(i2->Flags & EXPR_F_NULL) && (ptr=strpbrk(i0->String, i2->String)) != NULL) + { + mssError(1,"EXP","WARNING!! String contains invalid character asc=%d", (int)(*ptr)); + return -1; + } + if ((i0->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i1->Flags & EXPR_F_NULL) - escchars = ""; + escchars = ""; else - escchars = i1->String; + escchars = i1->String; if (tree->Alloc && tree->String) nmSysFree(tree->String); tree->Alloc = 0; ptr = strpbrk(i0->String, escchars); if (!ptr) ptr = strchr(i0->String, '\\'); - if (!ptr) { - /** shortcut if no need to escape anything **/ - tree->Alloc = 0; - tree->String = i0->String; - return 0; - } + if (!ptr) + { + /** shortcut if no need to escape anything **/ + tree->Alloc = 0; + tree->String = i0->String; + return 0; + } esccnt = 1; ptr++; - while (*ptr) { - if (strchr(escchars, *ptr) || *ptr == '\\') esccnt++; - ptr++; - } + while(*ptr) + { + if (strchr(escchars, *ptr) || *ptr == '\\') esccnt++; + ptr++; + } len = strlen(i0->String); - if (len + esccnt < 64) { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } else { - tree->Alloc = 1; - tree->String = nmSysMalloc(len + esccnt + 1); - } + if (len+esccnt < 64) + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + else + { + tree->Alloc = 1; + tree->String = nmSysMalloc(len+esccnt+1); + } ptr = i0->String; dst = tree->String; - while (*ptr) { - if (strchr(escchars, *ptr) || *ptr == '\\') - *(dst++) = '\\'; - *(dst++) = *(ptr++); - } + while(*ptr) + { + if (strchr(escchars, *ptr) || *ptr == '\\') + *(dst++) = '\\'; + *(dst++) = *(ptr++); + } *dst = '\0'; return 0; -} + } -int exp_fn_quote(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int len, quotecnt; + +int exp_fn_quote(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int len,quotecnt; char* ptr; char* dst; tree->DataType = DATA_T_STRING; - if (i0 && (i0->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING || i1) { - mssError(1, "EXP", "quote() requires one string parameter"); - return -1; - } + if (i0 && (i0->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING || i1) + { + mssError(1,"EXP","quote() requires one string parameter"); + return -1; + } len = strlen(i0->String); ptr = i0->String; quotecnt = 0; - while (*ptr) { - if (*ptr == '\\' || *ptr == '"') quotecnt++; - ptr++; - } + while(*ptr) + { + if (*ptr == '\\' || *ptr == '"') quotecnt++; + ptr++; + } if (tree->Alloc && tree->String) nmSysFree(tree->String); tree->Alloc = 0; - if (len + quotecnt + 2 < 64) { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } else { - tree->Alloc = 1; - tree->String = nmSysMalloc(len + quotecnt + 2 + 1); - } + if (len + quotecnt + 2 < 64) + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + else + { + tree->Alloc = 1; + tree->String = nmSysMalloc(len + quotecnt + 2 + 1); + } ptr = i0->String; dst = tree->String; *(dst++) = '"'; - while (*ptr) { - if (*ptr == '\\' || *ptr == '"') - *(dst++) = '\\'; - *(dst++) = *(ptr++); - } + while(*ptr) + { + if (*ptr == '\\' || *ptr == '"') + *(dst++) = '\\'; + *(dst++) = *(ptr++); + } *(dst++) = '"'; *dst = '\0'; return 0; -} + } + -int exp_fn_eval(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_eval(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { pExpression eval_exp, parent; int rval; - if (i0 && !i1 && i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING || i1) { - mssError(1, "EXP", "eval() requires one string parameter"); - return -1; - } - for (parent = tree; parent->Parent; parent = parent->Parent); + if (i0 && !i1 && i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING || i1) + { + mssError(1,"EXP","eval() requires one string parameter"); + return -1; + } + for(parent=tree;parent->Parent;parent=parent->Parent); eval_exp = expCompileExpression(i0->String, objlist, parent->LxFlags, parent->CmpFlags); if (!eval_exp) return -1; - if ((rval = expEvalTree(eval_exp, objlist)) < 0) { - expFreeExpression(eval_exp); - return -1; - } + if ((rval=expEvalTree(eval_exp, objlist)) < 0) + { + expFreeExpression(eval_exp); + return -1; + } expCopyValue(eval_exp, tree, 1); expFreeExpression(eval_exp); return rval; -} + } -int exp_fn_round(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_round(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { int dec = 0; int i, v; double dv; long long mt, mv; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) { - mssError(1, "EXP", "round() requires a numeric parameter and an optional integer parameter"); - return -1; - } - if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) + { + mssError(1,"EXP","round() requires a numeric parameter and an optional integer parameter"); + return -1; + } + if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i1) dec = i1->Integer; tree->DataType = i0->DataType; - switch (i0->DataType) { - case DATA_T_INTEGER: - tree->Integer = i0->Integer; - if (dec < 0) { - v = 1; - for (i = dec; i < 0; i++) v *= 10; - if (tree->Integer > 0) - tree->Integer += (v / 2); - else - tree->Integer -= (v / 2); - tree->Integer /= v; - tree->Integer *= v; - } - break; - - case DATA_T_DOUBLE: - tree->Types.Double = i0->Types.Double; - dv = 1; - for (i = dec; i < 0; i++) dv *= 10; - for (i = 0; i < dec; i++) dv /= 10; - tree->Types.Double = tree->Types.Double / dv; - if (tree->Types.Double > 0) - tree->Types.Double = floor(tree->Types.Double + 0.5); - else - tree->Types.Double = ceil(tree->Types.Double - 0.5); - tree->Types.Double = tree->Types.Double*dv; - break; - - case DATA_T_MONEY: - mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; - if (dec < 4) { - mv = 1; - for (i = dec; i < 4; i++) mv *= 10; - if (mt > 0) - mt += (mv / 2); - else - mt -= (mv / 2); - mt /= mv; - mt *= mv; - } - tree->Types.Money.WholePart = mt / 10000; - mt = mt % 10000; - if (mt < 0) { - mt += 10000; - tree->Types.Money.WholePart -= 1; - } - tree->Types.Money.FractionPart = mt; - break; - } + switch(i0->DataType) + { + case DATA_T_INTEGER: + tree->Integer = i0->Integer; + if (dec < 0) + { + v = 1; + for(i=dec;i<0;i++) v *= 10; + if (tree->Integer > 0) + tree->Integer += (v/2); + else + tree->Integer -= (v/2); + tree->Integer /= v; + tree->Integer *= v; + } + break; + + case DATA_T_DOUBLE: + tree->Types.Double = i0->Types.Double; + dv = 1; + for(i=dec;i<0;i++) dv *= 10; + for(i=0;iTypes.Double = tree->Types.Double/dv; + if (tree->Types.Double > 0) + tree->Types.Double = floor(tree->Types.Double + 0.5); + else + tree->Types.Double = ceil(tree->Types.Double - 0.5); + tree->Types.Double = tree->Types.Double*dv; + break; + + case DATA_T_MONEY: + mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; + if (dec < 4) + { + mv = 1; + for(i=dec;i<4;i++) mv *= 10; + if (mt > 0) + mt += (mv/2); + else + mt -= (mv/2); + mt /= mv; + mt *= mv; + } + tree->Types.Money.WholePart = mt/10000; + mt = mt % 10000; + if (mt < 0) + { + mt += 10000; + tree->Types.Money.WholePart -= 1; + } + tree->Types.Money.FractionPart = mt; + break; + } return 0; -} + } + int -exp_fn_dateadd_mod_add(int v1, int v2, int mod, int* overflow) { +exp_fn_dateadd_mod_add(int v1, int v2, int mod, int* overflow) + { int rv; - rv = (v1 + v2) % mod; - *overflow = (v1 + v2) / mod; - if (rv < 0) { - *overflow -= 1; - rv += mod; - } + rv = (v1 + v2)%mod; + *overflow = (v1 + v2)/mod; + if (rv < 0) + { + *overflow -= 1; + rv += mod; + } return rv; -} + } + -int exp_fn_dateadd(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_dateadd(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { int diff_sec, diff_min, diff_hr, diff_day, diff_mo, diff_yr; int carry; /** checks **/ - if (!i0 || (i0->Flags & EXPR_F_NULL) || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "dateadd() first parameter must be non-null string or keyword date part"); - return -1; - } - if ((i1 && (i1->Flags & EXPR_F_NULL)) || (i2 && (i2->Flags & EXPR_F_NULL))) { - tree->DataType = DATA_T_DATETIME; - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i1 || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "dateadd() second parameter must be an integer (amount to add/subtract)"); - return -1; - } - if (!i2 || i2->DataType != DATA_T_DATETIME) { - mssError(1, "EXP", "dateadd() third parameter must be a datetime type"); - return -1; - } + if (!i0 || (i0->Flags & EXPR_F_NULL) || i0->DataType != DATA_T_STRING) + { + mssError(1, "EXP", "dateadd() first parameter must be non-null string or keyword date part"); + return -1; + } + if ((i1 && (i1->Flags & EXPR_F_NULL)) || (i2 && (i2->Flags & EXPR_F_NULL))) + { + tree->DataType = DATA_T_DATETIME; + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i1 || i1->DataType != DATA_T_INTEGER) + { + mssError(1, "EXP", "dateadd() second parameter must be an integer (amount to add/subtract)"); + return -1; + } + if (!i2 || i2->DataType != DATA_T_DATETIME) + { + mssError(1, "EXP", "dateadd() third parameter must be a datetime type"); + return -1; + } /** ok, we're good. set up for returning the value **/ tree->DataType = DATA_T_DATETIME; - memcpy(&tree->Types.Date, &i2->Types.Date, sizeof (DateTime)); + memcpy(&tree->Types.Date, &i2->Types.Date, sizeof(DateTime)); diff_sec = diff_min = diff_hr = diff_day = diff_mo = diff_yr = 0; if (!strcmp(i0->String, "second")) - diff_sec = i1->Integer; + diff_sec = i1->Integer; else if (!strcmp(i0->String, "minute")) - diff_min = i1->Integer; + diff_min = i1->Integer; else if (!strcmp(i0->String, "hour")) - diff_hr = i1->Integer; + diff_hr = i1->Integer; else if (!strcmp(i0->String, "day")) - diff_day = i1->Integer; + diff_day = i1->Integer; else if (!strcmp(i0->String, "month")) - diff_mo = i1->Integer; + diff_mo = i1->Integer; else if (!strcmp(i0->String, "year")) - diff_yr = i1->Integer; - else { - mssError(1, "EXP", "dateadd() first parameter must be a valid date part (second/minute/hour/day/month/year)"); - return -1; - } + diff_yr = i1->Integer; + else + { + mssError(1, "EXP", "dateadd() first parameter must be a valid date part (second/minute/hour/day/month/year)"); + return -1; + } /** Do the add **/ tree->Types.Date.Part.Second = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Second, diff_sec, 60, &carry); @@ -1148,1284 +1341,889 @@ int exp_fn_dateadd(pExpression tree, pParamObjects objlist, pExpression i0, pExp tree->Types.Date.Part.Year += diff_yr; /** Adding days is more complicated **/ - while (diff_day > 0) { - if (tree->Types.Date.Part.Day >= (obj_month_days[tree->Types.Date.Part.Month] + ((tree->Types.Date.Part.Month == 1 && IS_LEAP_YEAR(tree->Types.Date.Part.Year + 1900)) ? 1 : 0))) { - tree->Types.Date.Part.Day = 0; - tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, 1, 12, &carry); - tree->Types.Date.Part.Year += carry; - } else { - tree->Types.Date.Part.Day++; - } - diff_day--; - } - while (diff_day < 0) { - if (tree->Types.Date.Part.Day == 0) { - tree->Types.Date.Part.Day = (obj_month_days[exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry)] + ((tree->Types.Date.Part.Month == 2 && IS_LEAP_YEAR(tree->Types.Date.Part.Year + 1900)) ? 1 : 0)) - 1; - tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry); - tree->Types.Date.Part.Year += carry; - } else { - tree->Types.Date.Part.Day--; - } - diff_day++; - } + while (diff_day > 0) + { + if (tree->Types.Date.Part.Day >= (obj_month_days[tree->Types.Date.Part.Month] + ((tree->Types.Date.Part.Month==1 && IS_LEAP_YEAR(tree->Types.Date.Part.Year+1900))?1:0))) + { + tree->Types.Date.Part.Day = 0; + tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, 1, 12, &carry); + tree->Types.Date.Part.Year += carry; + } + else + { + tree->Types.Date.Part.Day++; + } + diff_day--; + } + while (diff_day < 0) + { + if (tree->Types.Date.Part.Day == 0) + { + tree->Types.Date.Part.Day = (obj_month_days[exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry)] + ((tree->Types.Date.Part.Month==2 && IS_LEAP_YEAR(tree->Types.Date.Part.Year+1900))?1:0)) - 1; + tree->Types.Date.Part.Month = exp_fn_dateadd_mod_add(tree->Types.Date.Part.Month, -1, 12, &carry); + tree->Types.Date.Part.Year += carry; + } + else + { + tree->Types.Date.Part.Day--; + } + diff_day++; + } return 0; -} + } + -int exp_fn_truncate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_truncate(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { int dec = 0; int i, v; double dv; long long mt, mv; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) { - mssError(1, "EXP", "truncate() requires a numeric parameter and an optional integer parameter"); - return -1; - } - if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE && i0->DataType != DATA_T_MONEY) || (i1 && i1->DataType != DATA_T_INTEGER) || (i1 && i2)) + { + mssError(1,"EXP","truncate() requires a numeric parameter and an optional integer parameter"); + return -1; + } + if ((i0->Flags & EXPR_F_NULL) || (i1 && (i1->Flags & EXPR_F_NULL))) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i1) dec = i1->Integer; tree->DataType = i0->DataType; - switch (i0->DataType) { - case DATA_T_INTEGER: - tree->Integer = i0->Integer; - if (dec < 0) { - v = 1; - for (i = dec; i < 0; i++) v *= 10; - tree->Integer /= v; - tree->Integer *= v; - } - break; - - case DATA_T_DOUBLE: - tree->Types.Double = i0->Types.Double; - dv = 1; - for (i = dec; i < 0; i++) dv *= 10; - for (i = 0; i < dec; i++) dv /= 10; - tree->Types.Double = tree->Types.Double / dv; - if (tree->Types.Double > 0) - tree->Types.Double = floor(tree->Types.Double + 0.000001); - else - tree->Types.Double = ceil(tree->Types.Double - 0.000001); - tree->Types.Double = tree->Types.Double*dv; - break; - - case DATA_T_MONEY: - mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; - if (dec < 4) { - mv = 1; - for (i = dec; i < 4; i++) mv *= 10; - mt /= mv; - mt *= mv; - } - tree->Types.Money.WholePart = mt / 10000; - mt = mt % 10000; - if (mt < 0) { - mt += 10000; - tree->Types.Money.WholePart -= 1; - } - tree->Types.Money.FractionPart = mt; - break; - } + switch(i0->DataType) + { + case DATA_T_INTEGER: + tree->Integer = i0->Integer; + if (dec < 0) + { + v = 1; + for(i=dec;i<0;i++) v *= 10; + tree->Integer /= v; + tree->Integer *= v; + } + break; + + case DATA_T_DOUBLE: + tree->Types.Double = i0->Types.Double; + dv = 1; + for(i=dec;i<0;i++) dv *= 10; + for(i=0;iTypes.Double = tree->Types.Double/dv; + if (tree->Types.Double > 0) + tree->Types.Double = floor(tree->Types.Double + 0.000001); + else + tree->Types.Double = ceil(tree->Types.Double - 0.000001); + tree->Types.Double = tree->Types.Double*dv; + break; + + case DATA_T_MONEY: + mt = i0->Types.Money.WholePart * 10000 + i0->Types.Money.FractionPart; + if (dec < 4) + { + mv = 1; + for(i=dec;i<4;i++) mv *= 10; + mt /= mv; + mt *= mv; + } + tree->Types.Money.WholePart = mt/10000; + mt = mt % 10000; + if (mt < 0) + { + mt += 10000; + tree->Types.Money.WholePart -= 1; + } + tree->Types.Money.FractionPart = mt; + break; + } return 0; -} + } /*** constrain(value, min, max) ***/ -int exp_fn_constrain(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!i0 || !i1 || !i2 || (i0->DataType != i1->DataType) || i0->DataType != i2->DataType || !(i0->DataType == DATA_T_INTEGER || i0->DataType == DATA_T_MONEY || i0->DataType == DATA_T_DOUBLE)) { - mssError(1, "EXP", "constrain() requires three numeric parameters of the same data type"); - return -1; - } +int exp_fn_constrain(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!i0 || !i1 || !i2 || (i0->DataType != i1->DataType) || i0->DataType != i2->DataType || !(i0->DataType == DATA_T_INTEGER || i0->DataType == DATA_T_MONEY || i0->DataType == DATA_T_DOUBLE)) + { + mssError(1,"EXP","constrain() requires three numeric parameters of the same data type"); + return -1; + } tree->DataType = i0->DataType; - if ((i0->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if ((i0->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } /* check min */ - if (!(i1->Flags & EXPR_F_NULL)) { - switch (i0->DataType) { - case DATA_T_INTEGER: - if (objDataCompare(i0->DataType, &(i0->Integer), i1->DataType, &(i1->Integer)) < 0) { - tree->Integer = i1->Integer; - return 0; - } - break; - case DATA_T_DOUBLE: - if (objDataCompare(i0->DataType, &(i0->Types.Double), i1->DataType, &(i1->Types.Double)) < 0) { - tree->Types.Double = i1->Types.Double; - return 0; - } - break; - case DATA_T_MONEY: - if (objDataCompare(i0->DataType, &(i0->Types.Money), i1->DataType, &(i1->Types.Money)) < 0) { - tree->Types.Money = i1->Types.Money; - return 0; - } - break; - } - } + if (!(i1->Flags & EXPR_F_NULL)) + { + switch(i0->DataType) + { + case DATA_T_INTEGER: + if (objDataCompare(i0->DataType, &(i0->Integer), i1->DataType, &(i1->Integer)) < 0) + { + tree->Integer = i1->Integer; + return 0; + } + break; + case DATA_T_DOUBLE: + if (objDataCompare(i0->DataType, &(i0->Types.Double), i1->DataType, &(i1->Types.Double)) < 0) + { + tree->Types.Double = i1->Types.Double; + return 0; + } + break; + case DATA_T_MONEY: + if (objDataCompare(i0->DataType, &(i0->Types.Money), i1->DataType, &(i1->Types.Money)) < 0) + { + tree->Types.Money = i1->Types.Money; + return 0; + } + break; + } + } /* check max */ - if (!(i2->Flags & EXPR_F_NULL)) { - switch (i0->DataType) { - case DATA_T_INTEGER: - if (objDataCompare(i0->DataType, &(i0->Integer), i2->DataType, &(i2->Integer)) > 0) { - tree->Integer = i2->Integer; - return 0; - } - break; - case DATA_T_DOUBLE: - if (objDataCompare(i0->DataType, &(i0->Types.Double), i2->DataType, &(i2->Types.Double)) > 0) { - tree->Types.Double = i2->Types.Double; - return 0; - } - break; - case DATA_T_MONEY: - if (objDataCompare(i0->DataType, &(i0->Types.Money), i2->DataType, &(i2->Types.Money)) > 0) { - tree->Types.Money = i2->Types.Money; - return 0; - } - break; - } - } + if (!(i2->Flags & EXPR_F_NULL)) + { + switch(i0->DataType) + { + case DATA_T_INTEGER: + if (objDataCompare(i0->DataType, &(i0->Integer), i2->DataType, &(i2->Integer)) > 0) + { + tree->Integer = i2->Integer; + return 0; + } + break; + case DATA_T_DOUBLE: + if (objDataCompare(i0->DataType, &(i0->Types.Double), i2->DataType, &(i2->Types.Double)) > 0) + { + tree->Types.Double = i2->Types.Double; + return 0; + } + break; + case DATA_T_MONEY: + if (objDataCompare(i0->DataType, &(i0->Types.Money), i2->DataType, &(i2->Types.Money)) > 0) + { + tree->Types.Money = i2->Types.Money; + return 0; + } + break; + } + } /* go with actual value */ - switch (i0->DataType) { - case DATA_T_INTEGER: - tree->Integer = i0->Integer; - break; - case DATA_T_DOUBLE: - tree->Types.Double = i0->Types.Double; - break; - case DATA_T_MONEY: - tree->Types.Money = i0->Types.Money; - break; - } + switch(i0->DataType) + { + case DATA_T_INTEGER: + tree->Integer = i0->Integer; + break; + case DATA_T_DOUBLE: + tree->Types.Double = i0->Types.Double; + break; + case DATA_T_MONEY: + tree->Types.Money = i0->Types.Money; + break; + } return 0; -} + } + -int exp_fn_radians(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_radians(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; double pi = 3.14159265358979323846; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "radians() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","radians() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; - tree->Types.Double = d * pi / 180.0; + d = i0->Types.Double; + tree->Types.Double = d*pi/180.0; return 0; -} + } -int exp_fn_degrees(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_degrees(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; double pi = 3.14159265358979323846; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "degrees() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","degrees() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; - tree->Types.Double = d * 180.0 / pi; + d = i0->Types.Double; + tree->Types.Double = d*180.0/pi; return 0; -} + } + -int exp_fn_sin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_sin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "sin() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","sin() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; tree->Types.Double = sin(d); return 0; -} + } -int exp_fn_cos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_cos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "cos() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","cos() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; tree->Types.Double = cos(d); return 0; -} + } -int exp_fn_tan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_tan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "tan() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","tan() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; tree->Types.Double = tan(d); return 0; -} + } + -int exp_fn_asin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_asin(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "asin() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","asin() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = asin(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; -} + } + -int exp_fn_acos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_acos(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "acos() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","acos() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = acos(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; -} + } -int exp_fn_atan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_atan(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "atan() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","atan() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = atan(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; -} + } + -int exp_fn_atan2(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_atan2(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d1, d2; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || !i1 || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) { - mssError(1, "EXP", "atan2() requires two numeric (integer or double) parameters"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || !i1 || (i1->DataType != DATA_T_INTEGER && i1->DataType != DATA_T_DOUBLE)) + { + mssError(1,"EXP","atan2() requires two numeric (integer or double) parameters"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d1 = i0->Integer; + d1 = i0->Integer; else - d1 = i0->Types.Double; + d1 = i0->Types.Double; if (i1->DataType == DATA_T_INTEGER) - d2 = i1->Integer; + d2 = i1->Integer; else - d2 = i1->Types.Double; + d2 = i1->Types.Double; errno = 0; tree->Types.Double = atan2(d1, d2); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; -} + } + -int exp_fn_sqrt(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_sqrt(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { double d; - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "sqrt() requires a single numeric (integer or double) parameter"); - return -1; - } + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","sqrt() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = DATA_T_DOUBLE; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - d = i0->Integer; + d = i0->Integer; else - d = i0->Types.Double; + d = i0->Types.Double; errno = 0; tree->Types.Double = sqrt(d); if (errno == EDOM) - tree->Flags |= EXPR_F_NULL; + tree->Flags |= EXPR_F_NULL; return 0; -} - -int exp_fn_square(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) { - mssError(1, "EXP", "square() requires a single numeric (integer or double) parameter"); - return -1; } + + +int exp_fn_square(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!i0 || (i0->DataType != DATA_T_INTEGER && i0->DataType != DATA_T_DOUBLE) || i1) + { + mssError(1,"EXP","square() requires a single numeric (integer or double) parameter"); + return -1; + } tree->DataType = i0->DataType; - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } if (i0->DataType == DATA_T_INTEGER) - tree->Integer = i0->Integer * i0->Integer; + tree->Integer = i0->Integer * i0->Integer; else - tree->Types.Double = i0->Types.Double * i0->Types.Double; + tree->Types.Double = i0->Types.Double * i0->Types.Double; return 0; -} + } -int exp_fn_count(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + +int exp_fn_count(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { pExpression new_exp; /** Init the Aggregate computation expression? **/ - if (!tree->AggExp) { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_PLUS; - tree->AggExp->DataType = DATA_T_INTEGER; - tree->AggExp->Integer = 0; - tree->AggExp->AggLevel = 1; - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->DataType = DATA_T_INTEGER; - new_exp->Integer = 1; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - } + if (!tree->AggExp) + { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_PLUS; + tree->AggExp->DataType = DATA_T_INTEGER; + tree->AggExp->Integer = 0; + tree->AggExp->AggLevel = 1; + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->DataType = DATA_T_INTEGER; + new_exp->Integer = 1; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + } if (tree->Flags & EXPR_F_AGGLOCKED) return 0; /** Compute the possibly incremented value **/ - if (!(i0->Flags & EXPR_F_NULL)) { - expCopyValue(tree->AggExp, (pExpression) (tree->AggExp->Children.Items[1]), 0); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 0); - } + if (!(i0->Flags & EXPR_F_NULL)) + { + expCopyValue(tree->AggExp, (pExpression)(tree->AggExp->Children.Items[1]), 0); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 0); + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; -} + } + -int exp_fn_avg(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_avg(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { pExpression new_exp, new_subexp; pExpression sumexp, cntexp, s_accumexp, c_accumexp, valueexp; /** Init the Aggregate computation expression? **/ - if (!tree->AggExp) { - /** Overall expression is sum(x) / count(x) **/ - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_DIVIDE; - tree->AggExp->DataType = DATA_T_INTEGER; - tree->AggExp->Integer = 0; - tree->AggExp->AggLevel = 1; - tree->AggExp->Flags |= EXPR_F_NULL; - - /** Now for the sum(x) part **/ - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_PLUS; - new_exp->DataType = DATA_T_INTEGER; - new_exp->Integer = 0; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - - /** Now for the count(x) part **/ - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_PLUS; - new_exp->DataType = DATA_T_INTEGER; - new_exp->Integer = 0; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - new_subexp = expAllocExpression(); - new_subexp->NodeType = EXPR_N_INTEGER; - new_subexp->DataType = DATA_T_INTEGER; - new_subexp->Integer = 1; - new_subexp->AggLevel = 1; - expAddNode(new_exp, new_subexp); - } - - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { - /** Just to make things easier to read... **/ - sumexp = (pExpression) (tree->AggExp->Children.Items[0]); - cntexp = (pExpression) (tree->AggExp->Children.Items[1]); - s_accumexp = (pExpression) (sumexp->Children.Items[0]); - valueexp = (pExpression) (sumexp->Children.Items[1]); - c_accumexp = (pExpression) (cntexp->Children.Items[0]); - - /** Init the sum() part? **/ - if (tree->AggCount == 0) { - tree->AggExp->Flags &= ~EXPR_F_NULL; - sumexp->DataType = i0->DataType; - sumexp->String = sumexp->Types.StringBuf; - sumexp->Alloc = 0; - sumexp->String[0] = '\0'; - sumexp->Integer = 0; - sumexp->Types.Double = 0; - sumexp->Types.Money.FractionPart = 0; - sumexp->Types.Money.WholePart = 0; - - cntexp->Integer = 0; - } - - /** Do the count() part. **/ - expCopyValue(cntexp, c_accumexp, 0); - - /** Do the sum() part. **/ - expCopyValue(sumexp, s_accumexp, 1); - expCopyValue(i0, valueexp, 0); - valueexp->NodeType = expDataTypeToNodeType(i0->DataType); - s_accumexp->NodeType = expDataTypeToNodeType(sumexp->DataType); - - /** Eval the expression and copy the result. **/ - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - - /** - switch(i0->DataType) - { - case DATA_T_INTEGER: - tree->DataType = DATA_T_INTEGER; - tree->AggCount++; - tree->AggExp->Integer += i0->Integer; - tree->Integer = tree->AggExp->Integer / tree->AggCount; - break; - case DATA_T_DOUBLE: - tree->DataType = DATA_T_DOUBLE; - tree->AggCount++; - tree->AggExp->Types.Double += i0->Types.Double; - tree->Types.Double = tree->AggExp->Types.Double / tree->AggCount; - break; - } - **/ - } else { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } + if (!tree->AggExp) + { + /** Overall expression is sum(x) / count(x) **/ + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_DIVIDE; + tree->AggExp->DataType = DATA_T_INTEGER; + tree->AggExp->Integer = 0; + tree->AggExp->AggLevel = 1; + tree->AggExp->Flags |= EXPR_F_NULL; + + /** Now for the sum(x) part **/ + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_PLUS; + new_exp->DataType = DATA_T_INTEGER; + new_exp->Integer = 0; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); + + /** Now for the count(x) part **/ + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_PLUS; + new_exp->DataType = DATA_T_INTEGER; + new_exp->Integer = 0; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->AggLevel = 1; + expAddNode(new_exp, new_subexp); + new_subexp = expAllocExpression(); + new_subexp->NodeType = EXPR_N_INTEGER; + new_subexp->DataType = DATA_T_INTEGER; + new_subexp->Integer = 1; + new_subexp->AggLevel = 1; + expAddNode(new_exp,new_subexp); + } + + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) + { + /** Just to make things easier to read... **/ + sumexp = (pExpression)(tree->AggExp->Children.Items[0]); + cntexp = (pExpression)(tree->AggExp->Children.Items[1]); + s_accumexp = (pExpression)(sumexp->Children.Items[0]); + valueexp = (pExpression)(sumexp->Children.Items[1]); + c_accumexp = (pExpression)(cntexp->Children.Items[0]); + + /** Init the sum() part? **/ + if (tree->AggCount == 0) + { + tree->AggExp->Flags &= ~EXPR_F_NULL; + sumexp->DataType = i0->DataType; + sumexp->String = sumexp->Types.StringBuf; + sumexp->Alloc = 0; + sumexp->String[0] = '\0'; + sumexp->Integer = 0; + sumexp->Types.Double = 0; + sumexp->Types.Money.FractionPart = 0; + sumexp->Types.Money.WholePart = 0; + + cntexp->Integer = 0; + } + + /** Do the count() part. **/ + expCopyValue(cntexp, c_accumexp, 0); + + /** Do the sum() part. **/ + expCopyValue(sumexp, s_accumexp, 1); + expCopyValue(i0, valueexp, 0); + valueexp->NodeType = expDataTypeToNodeType(i0->DataType); + s_accumexp->NodeType = expDataTypeToNodeType(sumexp->DataType); + + /** Eval the expression and copy the result. **/ + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + + /** + switch(i0->DataType) + { + case DATA_T_INTEGER: + tree->DataType = DATA_T_INTEGER; + tree->AggCount++; + tree->AggExp->Integer += i0->Integer; + tree->Integer = tree->AggExp->Integer / tree->AggCount; + break; + case DATA_T_DOUBLE: + tree->DataType = DATA_T_DOUBLE; + tree->AggCount++; + tree->AggExp->Types.Double += i0->Types.Double; + tree->Types.Double = tree->AggExp->Types.Double / tree->AggCount; + break; + } + **/ + } + else + { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; -} + } + -int exp_fn_sum(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { +int exp_fn_sum(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { pExpression new_exp; - if (!tree->AggExp) { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_PLUS; - tree->AggExp->DataType = DATA_T_INTEGER; - tree->AggExp->Integer = 0; - tree->AggExp->AggLevel = 1; - tree->AggExp->Flags |= EXPR_F_NULL; - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - new_exp = expAllocExpression(); - new_exp->NodeType = EXPR_N_INTEGER; - new_exp->AggLevel = 1; - expAddNode(tree->AggExp, new_exp); - } + if (!tree->AggExp) + { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_PLUS; + tree->AggExp->DataType = DATA_T_INTEGER; + tree->AggExp->Integer = 0; + tree->AggExp->AggLevel = 1; + tree->AggExp->Flags |= EXPR_F_NULL; + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + new_exp = expAllocExpression(); + new_exp->NodeType = EXPR_N_INTEGER; + new_exp->AggLevel = 1; + expAddNode(tree->AggExp, new_exp); + } /*if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL;*/ - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { - if (tree->AggCount == 0) { - tree->AggExp->Flags &= ~EXPR_F_NULL; - tree->AggExp->DataType = i0->DataType; - if (tree->AggExp->Alloc && tree->AggExp->String) nmSysFree(tree->AggExp->String); - tree->AggExp->Alloc = 0; - tree->AggExp->String = tree->AggExp->Types.StringBuf; - tree->AggExp->String[0] = '\0'; - tree->AggExp->Integer = 0; - tree->AggExp->Types.Double = 0; - tree->AggExp->Types.Money.FractionPart = 0; - tree->AggExp->Types.Money.WholePart = 0; - } - expCopyValue(tree->AggExp, (pExpression) (tree->AggExp->Children.Items[0]), 1); - expCopyValue(i0, (pExpression) (tree->AggExp->Children.Items[1]), 0); - ((pExpression) (tree->AggExp->Children.Items[1]))->NodeType = expDataTypeToNodeType(i0->DataType); - ((pExpression) (tree->AggExp->Children.Items[0]))->NodeType = expDataTypeToNodeType(tree->AggExp->DataType); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - } else { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) + { + if (tree->AggCount == 0) + { + tree->AggExp->Flags &= ~EXPR_F_NULL; + tree->AggExp->DataType = i0->DataType; + if (tree->AggExp->Alloc && tree->AggExp->String) nmSysFree(tree->AggExp->String); + tree->AggExp->Alloc = 0; + tree->AggExp->String = tree->AggExp->Types.StringBuf; + tree->AggExp->String[0] = '\0'; + tree->AggExp->Integer = 0; + tree->AggExp->Types.Double = 0; + tree->AggExp->Types.Money.FractionPart = 0; + tree->AggExp->Types.Money.WholePart = 0; + } + expCopyValue(tree->AggExp, (pExpression)(tree->AggExp->Children.Items[0]), 1); + expCopyValue(i0, (pExpression)(tree->AggExp->Children.Items[1]), 0); + ((pExpression)(tree->AggExp->Children.Items[1]))->NodeType = expDataTypeToNodeType(i0->DataType); + ((pExpression)(tree->AggExp->Children.Items[0]))->NodeType = expDataTypeToNodeType(tree->AggExp->DataType); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + } + else + { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; -} - -int exp_fn_max(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - pExpression exp, subexp; - - /** Initialize the aggexp tree? **/ - if (!tree->AggExp) { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_FUNCTION; - tree->AggExp->AggLevel = 1; - tree->AggExp->Name = "condition"; - tree->AggExp->NameAlloc = 0; - tree->AggExp->Flags |= EXPR_F_NULL; - exp = expAllocExpression(); - exp->NodeType = EXPR_N_COMPARE; - exp->CompareType = MLX_CMP_GREATER; - exp->AggLevel = 1; - subexp = expAllocExpression(); - subexp->AggLevel = 1; - expAddNode(tree->AggExp, exp); - expAddNode(tree->AggExp, expLinkExpression(i0)); - expAddNode(tree->AggExp, subexp); - expAddNode(exp, expLinkExpression(i0)); - expAddNode(exp, expLinkExpression(subexp)); } - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { - if (tree->AggCount == 0) { - tree->AggExp->Flags &= ~EXPR_F_NULL; - tree->DataType = i0->DataType; - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - tree->String[0] = '\0'; - tree->Integer = 0; - tree->Types.Double = 0; - tree->Types.Money.FractionPart = 0; - tree->Types.Money.WholePart = 0; - expCopyValue(i0, tree, 0); - } - subexp = ((pExpression) (tree->AggExp->Children.Items[2])); - subexp->NodeType = expDataTypeToNodeType(i0->DataType); - expCopyValue(tree, subexp, 1); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - } else { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; - return 0; -} -int exp_fn_min(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - pExpression exp, subexp; +int exp_fn_max(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + pExpression exp,subexp; /** Initialize the aggexp tree? **/ - if (!tree->AggExp) { - tree->AggExp = expAllocExpression(); - tree->AggExp->NodeType = EXPR_N_FUNCTION; - tree->AggExp->AggLevel = 1; - tree->AggExp->Name = "condition"; - tree->AggExp->NameAlloc = 0; - tree->AggExp->Flags |= EXPR_F_NULL; - exp = expAllocExpression(); - exp->NodeType = EXPR_N_COMPARE; - exp->CompareType = MLX_CMP_LESS; - exp->AggLevel = 1; - subexp = expAllocExpression(); - subexp->AggLevel = 1; - expAddNode(tree->AggExp, exp); - expAddNode(tree->AggExp, expLinkExpression(i0)); - expAddNode(tree->AggExp, subexp); - expAddNode(exp, expLinkExpression(i0)); - expAddNode(exp, expLinkExpression(subexp)); - } - - if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) { - if (tree->AggCount == 0) { - tree->AggExp->Flags &= ~EXPR_F_NULL; - tree->DataType = i0->DataType; - tree->String = tree->Types.StringBuf; - tree->String[0] = '\0'; - tree->Alloc = 0; - tree->Integer = 0; - tree->Types.Double = 0; - tree->Types.Money.FractionPart = 0; - tree->Types.Money.WholePart = 0; - expCopyValue(i0, tree, 0); - } - subexp = ((pExpression) (tree->AggExp->Children.Items[2])); - subexp->NodeType = expDataTypeToNodeType(i0->DataType); - expCopyValue(tree, subexp, 1); - exp_internal_EvalTree(tree->AggExp, objlist); - expCopyValue(tree->AggExp, tree, 1); - tree->AggCount++; - } else { - if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; - return 0; -} - -int exp_fn_first(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) { - if (tree->AggCount == 0) { - expCopyValue(i0, tree, 1); - } - tree->AggCount++; - } else { - if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; - } - tree->Flags |= EXPR_F_AGGLOCKED; - return 0; -} - -int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) { - expCopyValue(i0, tree, 1); - tree->AggCount++; - } else { - if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; - } + if (!tree->AggExp) + { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_FUNCTION; + tree->AggExp->AggLevel = 1; + tree->AggExp->Name = "condition"; + tree->AggExp->NameAlloc = 0; + tree->AggExp->Flags |= EXPR_F_NULL; + exp = expAllocExpression(); + exp->NodeType = EXPR_N_COMPARE; + exp->CompareType = MLX_CMP_GREATER; + exp->AggLevel = 1; + subexp = expAllocExpression(); + subexp->AggLevel = 1; + expAddNode(tree->AggExp, exp); + expAddNode(tree->AggExp, expLinkExpression(i0)); + expAddNode(tree->AggExp, subexp); + expAddNode(exp, expLinkExpression(i0)); + expAddNode(exp, expLinkExpression(subexp)); + } + + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) + { + if (tree->AggCount == 0) + { + tree->AggExp->Flags &= ~EXPR_F_NULL; + tree->DataType = i0->DataType; + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + tree->String[0] = '\0'; + tree->Integer = 0; + tree->Types.Double = 0; + tree->Types.Money.FractionPart = 0; + tree->Types.Money.WholePart = 0; + expCopyValue(i0,tree,0); + } + subexp = ((pExpression)(tree->AggExp->Children.Items[2])); + subexp->NodeType = expDataTypeToNodeType(i0->DataType); + expCopyValue(tree, subexp, 1); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + } + else + { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } tree->Flags |= EXPR_F_AGGLOCKED; return 0; -} - -int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - wchar_t firstChar; - size_t bytesParsed; - - tree->DataType = DATA_T_INTEGER; - if (!i0) { - mssError(1, "EXP", "Parameter required for ascii() function."); - return -1; - } - if (i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "ascii() function takes a string parameter."); - return -1; - } - if (i0->String[0] == '\0') - tree->Flags |= EXPR_F_NULL; - - /** Parse first wide char **/ - bytesParsed = mbrtowc(&firstChar, i0->String, strlen(i0->String), NULL); - if (bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) { - goto errorInvalidUTF8Char; - } else - tree->Integer = firstChar; - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} - -int exp_fn_utf8_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - char* ptr; - size_t tmpLen; - - tree->DataType = DATA_T_INTEGER; - if (!i0 || !i1) { - mssError(1, "EXP", "Two string parameters required for charindex()"); - return -1; - } - if ((i0->Flags | i1->Flags) & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { - mssError(1, "EXP", "Two string parameters required for charindex()"); - return -1; - } - ptr = strstr(i1->String, i0->String); - if (ptr == NULL) - tree->Integer = 0; - else{ - tmpLen = mbstowcs(NULL, i1->String, ptr - i1->String) + 1; - if(tmpLen == (size_t)-1) - goto errorInvalidUTF8Char; - tree->Integer = tmpLen; } - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} -int exp_fn_utf8_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int i, oldStrLen, longStrLen, newStrLen; +int exp_fn_min(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + pExpression exp,subexp; - tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for upper()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - oldStrLen = strlen(i0->String); - wchar_t longBuffer[oldStrLen + 1]; - longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - for (i = 0; i < oldStrLen + 1; i++) { - longBuffer[i] = towupper(longBuffer[i]); - } - newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); - if(newStrLen == (size_t)-1) - goto errorCharacterConversion; - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (newStrLen < 63) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } else { - tree->String = (char*) nmSysMalloc(newStrLen + 1); - tree->Alloc = 1; - } - newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); + /** Initialize the aggexp tree? **/ + if (!tree->AggExp) + { + tree->AggExp = expAllocExpression(); + tree->AggExp->NodeType = EXPR_N_FUNCTION; + tree->AggExp->AggLevel = 1; + tree->AggExp->Name = "condition"; + tree->AggExp->NameAlloc = 0; + tree->AggExp->Flags |= EXPR_F_NULL; + exp = expAllocExpression(); + exp->NodeType = EXPR_N_COMPARE; + exp->CompareType = MLX_CMP_LESS; + exp->AggLevel = 1; + subexp = expAllocExpression(); + subexp->AggLevel = 1; + expAddNode(tree->AggExp, exp); + expAddNode(tree->AggExp, expLinkExpression(i0)); + expAddNode(tree->AggExp, subexp); + expAddNode(exp, expLinkExpression(i0)); + expAddNode(exp, expLinkExpression(subexp)); + } + + if (!(i0->Flags & EXPR_F_NULL) && !(tree->Flags & EXPR_F_AGGLOCKED)) + { + if (tree->AggCount == 0) + { + tree->AggExp->Flags &= ~EXPR_F_NULL; + tree->DataType = i0->DataType; + tree->String = tree->Types.StringBuf; + tree->String[0] = '\0'; + tree->Alloc = 0; + tree->Integer = 0; + tree->Types.Double = 0; + tree->Types.Money.FractionPart = 0; + tree->Types.Money.WholePart = 0; + expCopyValue(i0,tree,0); + } + subexp = ((pExpression)(tree->AggExp->Children.Items[2])); + subexp->NodeType = expDataTypeToNodeType(i0->DataType); + expCopyValue(tree, subexp, 1); + exp_internal_EvalTree(tree->AggExp, objlist); + expCopyValue(tree->AggExp, tree, 1); + tree->AggCount++; + } + else + { + if (tree->AggExp->Flags & EXPR_F_NULL) tree->Flags |= EXPR_F_NULL; + } + tree->Flags |= EXPR_F_AGGLOCKED; return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; - -errorCharacterConversion: - mssError(1, "EXP", "Error converting characters"); - return -1; -} - -int exp_fn_utf8_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int i, oldStrLen, longStrLen, newStrLen; - - tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for upper()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - oldStrLen = strlen(i0->String); - wchar_t longBuffer[oldStrLen + 1]; - longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - for (i = 0; i < oldStrLen + 1; i++) { - longBuffer[i] = towlower(longBuffer[i]); } - newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); - if(newStrLen == (size_t)-1) - goto errorCharacterConversion; - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - tree->Alloc = 0; - } - if (newStrLen < 63) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; - } else { - tree->String = (char*) nmSysMalloc(newStrLen + 1); - tree->Alloc = 1; - } - newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); - return 0; -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; - -errorCharacterConversion: - mssError(1, "EXP", "Error converting characters"); - return -1; -} -int exp_fn_utf8_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - size_t wideLen; - - tree->DataType = DATA_T_INTEGER; - if (i0 && i0->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for char_length()"); - return -1; - } - wideLen = mbstowcs(NULL, i0->String, strlen(i0->String) + 1); - if(wideLen == (size_t)-1) - goto errorInvalidUTF8Char; - tree->Integer = wideLen; - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} - -int exp_fn_utf8_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int offsetFromEnd, currentPos = 0, numScanned = 0; - size_t charStrLen, longStrLen, step = 0; - mbstate_t currentState; - - memset(¤tState, 0, sizeof(currentState)); - - if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "Invalid datatypes in right() function - takes (string,integer)"); - return -1; - } - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - } - charStrLen = strlen(i0->String); - longStrLen = mbstowcs(NULL, i0->String, charStrLen+1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - - offsetFromEnd = i1->Integer; - if (offsetFromEnd > longStrLen) offsetFromEnd = longStrLen; - if (offsetFromEnd < 0) offsetFromEnd = 0; - - while(numScanned < (longStrLen - offsetFromEnd)) { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - break; - numScanned++; - currentPos += step; - } - - tree->DataType = DATA_T_STRING; - tree->String = i0->String + currentPos; - tree->Alloc = 0; +int exp_fn_first(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) + { + if (tree->AggCount == 0) + { + expCopyValue(i0, tree, 1); + } + tree->AggCount++; + } + else + { + if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; + } + tree->Flags |= EXPR_F_AGGLOCKED; return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} - -int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - - size_t charStrLen, longStrLen, initial, len; - - if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); - return -1; - } - if (i2 && i2->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); - return -1; - } - - /** Free any previous string in preparation for these results **/ - if (tree->Alloc && tree->String) { - nmSysFree(tree->String); - tree->Alloc = 0; - } - tree->DataType = DATA_T_STRING; - - /** String lengths and character lengths and parameters **/ - initial = i0->Integer; - len = i2?i2->Integer:0; - charStrLen = strlen(i0->String); - longStrLen = mbstowcs(NULL, i0->String, charStrLen + 1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - - /** Check range of initial - shortcut if out of bounds **/ - if(initial > longStrLen) { - tree->Alloc = 0; - tree->String = i0->String + charStrLen; - return 0; - } - - /** Set length to length of string if too long **/ - if(initial + len - 1 > longStrLen || len <= 0) - len = longStrLen + 1 - initial; - - /** Shortcut for right, returning a pointer inside of the string **/ - if(initial + len - 1 >= longStrLen) { - /** Variables for right **/ - int currentPos = 0, step = 0, numScanned = 0; - mbstate_t currentState; - - /** Initialize current state **/ - memset(¤tState, 0, sizeof(currentState)); - - /** Scan over to the first char of the right substring to return **/ - while(numScanned < longStrLen - len) { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - break; - numScanned++; - currentPos += step; - } - - tree->Alloc = 0; - tree->String = i0->String + currentPos; } - /** Allocate a separate string and copy data **/ - else { - - /** Variables for substring in middle of string **/ - int currentPos = 0, step = 0, numScanned = 0, initialPos, i; - char * newStr; - mbstate_t currentState; - - memset(¤tState, 0, sizeof(currentState)); - - /** Scan to initial position of wanted substring **/ - while(numScanned < initial - 1) { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) { - tree->Alloc = 0; - tree->String = i0->String + charStrLen; - return 0; - } - numScanned++; - currentPos += step; - } - initialPos = currentPos; - - /** Scan to final position of wanted substring **/ - while(numScanned - initial < len - 1) { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - break; - numScanned++; - currentPos += step; - } - - /** Now initialPos is the first char and finalPos is one after last **/ - if(currentPos - initialPos > 63) { - tree->Alloc = 0; - newStr = tree->Types.StringBuf; - } - else { - tree->Alloc = 1; - newStr = nmSysMalloc(currentPos - initialPos + 1); - } - for(i = initialPos; i < currentPos; i++) { - newStr[i - initialPos] = i0->String[i]; - } - newStr[currentPos - initialPos] = '\0'; - tree->String = newStr; - } - - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} - -/*** Pad string expression i0 with integer expression i1 number of spaces ***/ -int exp_fn_utf8_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - size_t charStrLen, wideStrLen; - - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { - mssError(1, "EXP", "ralign() requires string parameter #1 and integer parameter #2"); - return -1; - } - tree->DataType = DATA_T_STRING; - if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (tree->Alloc && tree->String) nmSysFree(tree->String); - charStrLen = strlen(i0->String); - wideStrLen = mbstowcs(NULL, i0->String, charStrLen); - if(wideStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - if (wideStrLen >= i1->Integer) { - tree->Alloc = 0; - tree->String = i0->String; - } +int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + if (!(tree->Flags & EXPR_F_AGGLOCKED) && !(i0->Flags & EXPR_F_NULL)) + { + expCopyValue(i0, tree, 1); + tree->AggCount++; + } else - { - if (i1->Integer - wideStrLen + charStrLen >= 64) { - tree->Alloc = 1; - tree->String = (char*) nmSysMalloc(i1->Integer - wideStrLen + charStrLen + 1); - } else { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } - sprintf(tree->String, "%*.*s", i1->Integer, i1->Integer, i0->String); - } + { + if (tree->AggCount == 0) tree->Flags |= EXPR_F_NULL; + } + tree->Flags |= EXPR_F_AGGLOCKED; return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} - -/** escape(string, escchars, badchars) **/ -int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - - /** Variables **/ - int escCharLen, badCharLen, numEscapees = 0, i, j, strLen, readPos, insertPos; - wchar_t current; - mbstate_t state; - char * output, * esc, * bad; - size_t charLen, badStrLen, escStrLen; - - tree->DataType = DATA_T_STRING; - if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { - mssError(1, "EXP", "escape() requires two or three string parameters"); - return -1; } - if (i2 && i2->DataType != DATA_T_STRING) { - mssError(1, "EXP", "the optional third escape() parameter must be a string"); - bad = (i2->Flags & EXPR_F_NULL) ? "": i2->String; - return -1; - } - if ((i0->Flags & EXPR_F_NULL)) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - if (i1->Flags & EXPR_F_NULL) - esc = ""; - else - esc = i1->String; - if (tree->Alloc && tree->String) nmSysFree(tree->String); - /** The esc and bad parameters in wchar_t form **/ - strLen = strlen(i0->String); - escCharLen = strlen(esc); - badCharLen = strlen(bad); - wchar_t escBuf[escCharLen + 2], badBuf[badCharLen + 1]; - escStrLen = mbstowcs(escBuf, esc, escCharLen + 1); - if(escStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - escBuf[escStrLen] = '\\'; - escBuf[++escStrLen] = '\0'; - badStrLen = mbstowcs(badBuf, bad, badCharLen + 1); - if(badStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - - /** Scan through to find all chars to escape **/ - memset(&state, '\0', sizeof(state)); - for(i = 0; i0->String[i] != '\0';) { - charLen = mbrtowc(¤t, i0->String + i, strLen - i, &state); - if(charLen == (size_t)-1 || charLen == (size_t)-2) { - goto errorInvalidUTF8Char; - } - i += charLen; - for(j = 0; j < badStrLen; j++) { - if(current == badBuf[j]){ - goto errorInvalidChar; - } - } - for(j = 0; j < escStrLen; j++) { - if(current == escBuf[j]) { - numEscapees++; - break; - } - } - } - if(numEscapees == 0) { - tree->Alloc = 0; - tree->String = i0->String; - return 0; - } - - memset(&state, '\0', sizeof(state)); - if(numEscapees + strLen <= 63){ - output = tree->Types.StringBuf; - tree->Alloc = 0; - } - else{ - output = nmSysMalloc(numEscapees + strLen + 1); - tree->Alloc = 1; - } - for(readPos = 0, insertPos = 0; readPos < strLen;) { - charLen = mbrtowc(¤t, i0->String + readPos, strLen - readPos, &state); - for(j = 0; j < escStrLen; j++) { - if(current == escBuf[j]) { - output[insertPos] = '\\'; - insertPos++; - break; - } - } - while(charLen--) { - output[insertPos++] = i0->String[readPos++]; - } - } - output[numEscapees + strLen] = '\0'; - - tree->String = output; - return 0; - - /** Different types of errors **/ -errorInvalidChar: - mssError(1, "EXP", "WARNING!! String contains invalid character asc=%d", (int) (current)); - return -1; -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; -} int -exp_internal_DefineFunctions() { - - /** Function list for EXPR_N_FUNCTION nodes **/ - xhAdd(&EXP.Functions, "getdate", (char*) exp_fn_getdate); - xhAdd(&EXP.Functions, "user_name", (char*) exp_fn_user_name); - xhAdd(&EXP.Functions, "convert", (char*) exp_fn_convert); - xhAdd(&EXP.Functions, "wordify", (char*) exp_fn_wordify); - xhAdd(&EXP.Functions, "abs", (char*) exp_fn_abs); - xhAdd(&EXP.Functions, "condition", (char*) exp_fn_condition); - xhAdd(&EXP.Functions, "datepart", (char*) exp_fn_datepart); - xhAdd(&EXP.Functions, "isnull", (char*) exp_fn_isnull); - xhAdd(&EXP.Functions, "ltrim", (char*) exp_fn_ltrim); - xhAdd(&EXP.Functions, "lztrim", (char*) exp_fn_lztrim); - xhAdd(&EXP.Functions, "rtrim", (char*) exp_fn_rtrim); - xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); - xhAdd(&EXP.Functions, "replicate", (char*) exp_fn_replicate); - xhAdd(&EXP.Functions, "quote", (char*) exp_fn_quote); - xhAdd(&EXP.Functions, "eval", (char*) exp_fn_eval); - xhAdd(&EXP.Functions, "round", (char*) exp_fn_round); - xhAdd(&EXP.Functions, "dateadd", (char*) exp_fn_dateadd); - xhAdd(&EXP.Functions, "truncate", (char*) exp_fn_truncate); - xhAdd(&EXP.Functions, "constrain", (char*) exp_fn_constrain); - xhAdd(&EXP.Functions, "sin", (char*) exp_fn_sin); - xhAdd(&EXP.Functions, "cos", (char*) exp_fn_cos); - xhAdd(&EXP.Functions, "tan", (char*) exp_fn_tan); - xhAdd(&EXP.Functions, "asin", (char*) exp_fn_asin); - xhAdd(&EXP.Functions, "acos", (char*) exp_fn_acos); - xhAdd(&EXP.Functions, "atan", (char*) exp_fn_atan); - xhAdd(&EXP.Functions, "atan2", (char*) exp_fn_atan2); - xhAdd(&EXP.Functions, "sqrt", (char*) exp_fn_sqrt); - xhAdd(&EXP.Functions, "square", (char*) exp_fn_square); - xhAdd(&EXP.Functions, "degrees", (char*) exp_fn_degrees); - xhAdd(&EXP.Functions, "radians", (char*) exp_fn_radians); - - xhAdd(&EXP.Functions, "count", (char*) exp_fn_count); - xhAdd(&EXP.Functions, "avg", (char*) exp_fn_avg); - xhAdd(&EXP.Functions, "sum", (char*) exp_fn_sum); - xhAdd(&EXP.Functions, "max", (char*) exp_fn_max); - xhAdd(&EXP.Functions, "min", (char*) exp_fn_min); - xhAdd(&EXP.Functions, "first", (char*) exp_fn_first); - xhAdd(&EXP.Functions, "last", (char*) exp_fn_last); - - /** Reverse functions **/ - xhAdd(&EXP.ReverseFunctions, "isnull", (char*) exp_fn_reverse_isnull); - - /** UTF-8/ASCII dependent **/ - if (CxGlobals.CharacterMode == CharModeSigleByte) { - xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_ascii); - xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_charindex); - xhAdd(&EXP.Functions, "upper", (char*) exp_fn_upper); - xhAdd(&EXP.Functions, "lower", (char*) exp_fn_lower); - xhAdd(&EXP.Functions, "char_length", (char*) exp_fn_char_length); - xhAdd(&EXP.Functions, "right", (char*) exp_fn_right); - xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_ralign); - xhAdd(&EXP.Functions, "escape", (char*) exp_fn_escape); - } else { - xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_utf8_ascii); - xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_utf8_charindex); - xhAdd(&EXP.Functions, "upper", (char*) exp_fn_utf8_upper); - xhAdd(&EXP.Functions, "lower", (char*) exp_fn_utf8_lower); - xhAdd(&EXP.Functions, "char_length", (char*) exp_fn_utf8_char_length); - xhAdd(&EXP.Functions, "right", (char*) exp_fn_utf8_right); - xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); - xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); - } +exp_internal_DefineFunctions() + { + + /** Function list for EXPR_N_FUNCTION nodes **/ + xhAdd(&EXP.Functions, "getdate", (char*)exp_fn_getdate); + xhAdd(&EXP.Functions, "user_name", (char*)exp_fn_user_name); + xhAdd(&EXP.Functions, "convert", (char*)exp_fn_convert); + xhAdd(&EXP.Functions, "wordify", (char*)exp_fn_wordify); + xhAdd(&EXP.Functions, "abs", (char*)exp_fn_abs); + xhAdd(&EXP.Functions, "ascii", (char*)exp_fn_ascii); + xhAdd(&EXP.Functions, "condition", (char*)exp_fn_condition); + xhAdd(&EXP.Functions, "charindex", (char*)exp_fn_charindex); + xhAdd(&EXP.Functions, "upper", (char*)exp_fn_upper); + xhAdd(&EXP.Functions, "lower", (char*)exp_fn_lower); + xhAdd(&EXP.Functions, "char_length", (char*)exp_fn_char_length); + xhAdd(&EXP.Functions, "datepart", (char*)exp_fn_datepart); + xhAdd(&EXP.Functions, "isnull", (char*)exp_fn_isnull); + xhAdd(&EXP.Functions, "ltrim", (char*)exp_fn_ltrim); + xhAdd(&EXP.Functions, "lztrim", (char*)exp_fn_lztrim); + xhAdd(&EXP.Functions, "rtrim", (char*)exp_fn_rtrim); + xhAdd(&EXP.Functions, "substring", (char*)exp_fn_substring); + xhAdd(&EXP.Functions, "right", (char*)exp_fn_right); + xhAdd(&EXP.Functions, "ralign", (char*)exp_fn_ralign); + xhAdd(&EXP.Functions, "replicate", (char*)exp_fn_replicate); + xhAdd(&EXP.Functions, "escape", (char*)exp_fn_escape); + xhAdd(&EXP.Functions, "quote", (char*)exp_fn_quote); + xhAdd(&EXP.Functions, "eval", (char*)exp_fn_eval); + xhAdd(&EXP.Functions, "round", (char*)exp_fn_round); + xhAdd(&EXP.Functions, "dateadd", (char*)exp_fn_dateadd); + xhAdd(&EXP.Functions, "truncate", (char*)exp_fn_truncate); + xhAdd(&EXP.Functions, "constrain", (char*)exp_fn_constrain); + xhAdd(&EXP.Functions, "sin", (char*)exp_fn_sin); + xhAdd(&EXP.Functions, "cos", (char*)exp_fn_cos); + xhAdd(&EXP.Functions, "tan", (char*)exp_fn_tan); + xhAdd(&EXP.Functions, "asin", (char*)exp_fn_asin); + xhAdd(&EXP.Functions, "acos", (char*)exp_fn_acos); + xhAdd(&EXP.Functions, "atan", (char*)exp_fn_atan); + xhAdd(&EXP.Functions, "atan2", (char*)exp_fn_atan2); + xhAdd(&EXP.Functions, "sqrt", (char*)exp_fn_sqrt); + xhAdd(&EXP.Functions, "square", (char*)exp_fn_square); + xhAdd(&EXP.Functions, "degrees", (char*)exp_fn_degrees); + xhAdd(&EXP.Functions, "radians", (char*)exp_fn_radians); + + xhAdd(&EXP.Functions, "count", (char*)exp_fn_count); + xhAdd(&EXP.Functions, "avg", (char*)exp_fn_avg); + xhAdd(&EXP.Functions, "sum", (char*)exp_fn_sum); + xhAdd(&EXP.Functions, "max", (char*)exp_fn_max); + xhAdd(&EXP.Functions, "min", (char*)exp_fn_min); + xhAdd(&EXP.Functions, "first", (char*)exp_fn_first); + xhAdd(&EXP.Functions, "last", (char*)exp_fn_last); + + /** Reverse functions **/ + xhAdd(&EXP.ReverseFunctions, "isnull", (char*)exp_fn_reverse_isnull); return 0; -} + } From 9750ca58b058ed33fe2eecd6a9a5ce9c584c51a4 Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Tue, 28 Jun 2011 17:28:41 -0400 Subject: [PATCH 003/124] Re-fixed exp-functions.c Really applied utf-8 set of functions ot exp-functions.c. The last commit did not actually include these. --- centrallix/expression/exp_functions.c | 685 ++++++++++++++++++++++++-- 1 file changed, 633 insertions(+), 52 deletions(-) mode change 100644 => 100755 centrallix/expression/exp_functions.c diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c old mode 100644 new mode 100755 index af5d247e0..4858128df --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -2169,61 +2169,642 @@ int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpres return 0; } +int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + wchar_t firstChar; + size_t bytesParsed; + + tree->DataType = DATA_T_INTEGER; + if (!i0) + { + mssError(1, "EXP", "Parameter required for ascii() function."); + return -1; + } + if (i0->DataType != DATA_T_STRING) + { + mssError(1, "EXP", "ascii() function takes a string parameter."); + return -1; + } + if (i0->String[0] == '\0') + tree->Flags |= EXPR_F_NULL; + + /** Parse first wide char **/ + bytesParsed = mbrtowc(&firstChar, i0->String, strlen(i0->String), NULL); + if (bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) + { + goto errorInvalidUTF8Char; + } + else + tree->Integer = firstChar; + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } -int -exp_internal_DefineFunctions() +int exp_fn_utf8_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + char* ptr; + size_t tmpLen; + + tree->DataType = DATA_T_INTEGER; + if (!i0 || !i1) + { + mssError(1, "EXP", "Two string parameters required for charindex()"); + return -1; + } + if ((i0->Flags | i1->Flags) & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) + { + mssError(1, "EXP", "Two string parameters required for charindex()"); + return -1; + } + ptr = strstr(i1->String, i0->String); + if (ptr == NULL) + tree->Integer = 0; + else + { + tmpLen = mbstowcs(NULL, i1->String, ptr - i1->String) + 1; + if(tmpLen == (size_t)-1) + goto errorInvalidUTF8Char; + tree->Integer = tmpLen; + } + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } + +int exp_fn_utf8_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int i, oldStrLen, longStrLen, newStrLen; + + tree->DataType = DATA_T_STRING; + if (!i0 || i0->DataType != DATA_T_STRING) + { + mssError(1, "EXP", "One string parameter required for upper()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + oldStrLen = strlen(i0->String); + wchar_t longBuffer[oldStrLen + 1]; + longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + for (i = 0; i < oldStrLen + 1; i++) + { + longBuffer[i] = towupper(longBuffer[i]); + } + newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); + if(newStrLen == (size_t)-1) + goto errorCharacterConversion; + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (newStrLen < 63) + { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } + else + { + tree->String = (char*) nmSysMalloc(newStrLen + 1); + tree->Alloc = 1; + } + newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + +errorCharacterConversion: + mssError(1, "EXP", "Error converting characters"); + return -1; + } + +int exp_fn_utf8_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int i, oldStrLen, longStrLen, newStrLen; + + tree->DataType = DATA_T_STRING; + if (!i0 || i0->DataType != DATA_T_STRING) + { + mssError(1, "EXP", "One string parameter required for upper()"); + return -1; + } + if (i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + oldStrLen = strlen(i0->String); + wchar_t longBuffer[oldStrLen + 1]; + longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + for (i = 0; i < oldStrLen + 1; i++) + { + longBuffer[i] = towlower(longBuffer[i]); + } + newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); + if(newStrLen == (size_t)-1) + goto errorCharacterConversion; + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + tree->Alloc = 0; + } + if (newStrLen < 63) + { + tree->String = tree->Types.StringBuf; + tree->Alloc = 0; + } + else + { + tree->String = (char*) nmSysMalloc(newStrLen + 1); + tree->Alloc = 1; + } + newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + +errorCharacterConversion: + mssError(1, "EXP", "Error converting characters"); + return -1; + } + +int exp_fn_utf8_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + size_t wideLen; + + tree->DataType = DATA_T_INTEGER; + if (i0 && i0->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING) { + mssError(1, "EXP", "One string parameter required for char_length()"); + return -1; + } + wideLen = mbstowcs(NULL, i0->String, strlen(i0->String) + 1); + if(wideLen == (size_t)-1) + goto errorInvalidUTF8Char; + tree->Integer = wideLen; + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } + +int exp_fn_utf8_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + int offsetFromEnd, currentPos = 0, numScanned = 0; + size_t charStrLen, longStrLen, step = 0; + mbstate_t currentState; + + memset(¤tState, 0, sizeof(currentState)); + + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) + { + mssError(1, "EXP", "Invalid datatypes in right() function - takes (string,integer)"); + return -1; + } + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + } + charStrLen = strlen(i0->String); + longStrLen = mbstowcs(NULL, i0->String, charStrLen+1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + + offsetFromEnd = i1->Integer; + if (offsetFromEnd > longStrLen) offsetFromEnd = longStrLen; + if (offsetFromEnd < 0) offsetFromEnd = 0; + + while(numScanned < (longStrLen - offsetFromEnd)) + { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + break; + numScanned++; + currentPos += step; + } + + tree->DataType = DATA_T_STRING; + tree->String = i0->String + currentPos; + tree->Alloc = 0; + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } + +int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + + size_t charStrLen, longStrLen, initial, len; + + if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) + { + mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } + if (i2 && i2->DataType != DATA_T_INTEGER) + { + mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); + return -1; + } + + /** Free any previous string in preparation for these results **/ + if (tree->Alloc && tree->String) + { + nmSysFree(tree->String); + tree->Alloc = 0; + } + tree->DataType = DATA_T_STRING; + + /** String lengths and character lengths and parameters **/ + initial = i0->Integer; + len = i2?i2->Integer:0; + charStrLen = strlen(i0->String); + longStrLen = mbstowcs(NULL, i0->String, charStrLen + 1); + if(longStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + + /** Check range of initial - shortcut if out of bounds **/ + if(initial > longStrLen) + { + tree->Alloc = 0; + tree->String = i0->String + charStrLen; + return 0; + } + + /** Set length to length of string if too long **/ + if(initial + len - 1 > longStrLen || len <= 0) + len = longStrLen + 1 - initial; + + /** Shortcut for right, returning a pointer inside of the string **/ + if(initial + len - 1 >= longStrLen) + { + /** Variables for right **/ + int currentPos = 0, step = 0, numScanned = 0; + mbstate_t currentState; + + /** Initialize current state **/ + memset(¤tState, 0, sizeof(currentState)); + + /** Scan over to the first char of the right substring to return **/ + while(numScanned < longStrLen - len) + { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + break; + numScanned++; + currentPos += step; + } + + tree->Alloc = 0; + tree->String = i0->String + currentPos; + } + + /** Allocate a separate string and copy data **/ + else + { + + /** Variables for substring in middle of string **/ + int currentPos = 0, step = 0, numScanned = 0, initialPos, i; + char * newStr; + mbstate_t currentState; + + memset(¤tState, 0, sizeof(currentState)); + + /** Scan to initial position of wanted substring **/ + while(numScanned < initial - 1) + { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + { + tree->Alloc = 0; + tree->String = i0->String + charStrLen; + return 0; + } + numScanned++; + currentPos += step; + } + initialPos = currentPos; + + /** Scan to final position of wanted substring **/ + while(numScanned - initial < len - 1) + { + step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + goto errorInvalidUTF8Char; + if(step == 0) + break; + numScanned++; + currentPos += step; + } + + /** Now initialPos is the first char and finalPos is one after last **/ + if(currentPos - initialPos > 63) + { + tree->Alloc = 0; + newStr = tree->Types.StringBuf; + } + else + { + tree->Alloc = 1; + newStr = nmSysMalloc(currentPos - initialPos + 1); + } + for(i = initialPos; i < currentPos; i++) + { + newStr[i - initialPos] = i0->String[i]; + } + newStr[currentPos - initialPos] = '\0'; + tree->String = newStr; + } + + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } - /** Function list for EXPR_N_FUNCTION nodes **/ - xhAdd(&EXP.Functions, "getdate", (char*)exp_fn_getdate); - xhAdd(&EXP.Functions, "user_name", (char*)exp_fn_user_name); - xhAdd(&EXP.Functions, "convert", (char*)exp_fn_convert); - xhAdd(&EXP.Functions, "wordify", (char*)exp_fn_wordify); - xhAdd(&EXP.Functions, "abs", (char*)exp_fn_abs); - xhAdd(&EXP.Functions, "ascii", (char*)exp_fn_ascii); - xhAdd(&EXP.Functions, "condition", (char*)exp_fn_condition); - xhAdd(&EXP.Functions, "charindex", (char*)exp_fn_charindex); - xhAdd(&EXP.Functions, "upper", (char*)exp_fn_upper); - xhAdd(&EXP.Functions, "lower", (char*)exp_fn_lower); - xhAdd(&EXP.Functions, "char_length", (char*)exp_fn_char_length); - xhAdd(&EXP.Functions, "datepart", (char*)exp_fn_datepart); - xhAdd(&EXP.Functions, "isnull", (char*)exp_fn_isnull); - xhAdd(&EXP.Functions, "ltrim", (char*)exp_fn_ltrim); - xhAdd(&EXP.Functions, "lztrim", (char*)exp_fn_lztrim); - xhAdd(&EXP.Functions, "rtrim", (char*)exp_fn_rtrim); - xhAdd(&EXP.Functions, "substring", (char*)exp_fn_substring); - xhAdd(&EXP.Functions, "right", (char*)exp_fn_right); - xhAdd(&EXP.Functions, "ralign", (char*)exp_fn_ralign); - xhAdd(&EXP.Functions, "replicate", (char*)exp_fn_replicate); - xhAdd(&EXP.Functions, "escape", (char*)exp_fn_escape); - xhAdd(&EXP.Functions, "quote", (char*)exp_fn_quote); - xhAdd(&EXP.Functions, "eval", (char*)exp_fn_eval); - xhAdd(&EXP.Functions, "round", (char*)exp_fn_round); - xhAdd(&EXP.Functions, "dateadd", (char*)exp_fn_dateadd); - xhAdd(&EXP.Functions, "truncate", (char*)exp_fn_truncate); - xhAdd(&EXP.Functions, "constrain", (char*)exp_fn_constrain); - xhAdd(&EXP.Functions, "sin", (char*)exp_fn_sin); - xhAdd(&EXP.Functions, "cos", (char*)exp_fn_cos); - xhAdd(&EXP.Functions, "tan", (char*)exp_fn_tan); - xhAdd(&EXP.Functions, "asin", (char*)exp_fn_asin); - xhAdd(&EXP.Functions, "acos", (char*)exp_fn_acos); - xhAdd(&EXP.Functions, "atan", (char*)exp_fn_atan); - xhAdd(&EXP.Functions, "atan2", (char*)exp_fn_atan2); - xhAdd(&EXP.Functions, "sqrt", (char*)exp_fn_sqrt); - xhAdd(&EXP.Functions, "square", (char*)exp_fn_square); - xhAdd(&EXP.Functions, "degrees", (char*)exp_fn_degrees); - xhAdd(&EXP.Functions, "radians", (char*)exp_fn_radians); - - xhAdd(&EXP.Functions, "count", (char*)exp_fn_count); - xhAdd(&EXP.Functions, "avg", (char*)exp_fn_avg); - xhAdd(&EXP.Functions, "sum", (char*)exp_fn_sum); - xhAdd(&EXP.Functions, "max", (char*)exp_fn_max); - xhAdd(&EXP.Functions, "min", (char*)exp_fn_min); - xhAdd(&EXP.Functions, "first", (char*)exp_fn_first); - xhAdd(&EXP.Functions, "last", (char*)exp_fn_last); - - /** Reverse functions **/ - xhAdd(&EXP.ReverseFunctions, "isnull", (char*)exp_fn_reverse_isnull); +/*** Pad string expression i0 with integer expression i1 number of spaces ***/ +int exp_fn_utf8_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + size_t charStrLen, wideStrLen; + + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) + { + mssError(1, "EXP", "ralign() requires string parameter #1 and integer parameter #2"); + return -1; + } + tree->DataType = DATA_T_STRING; + if ((i0->Flags & EXPR_F_NULL) || (i1->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + + if (tree->Alloc && tree->String) nmSysFree(tree->String); + charStrLen = strlen(i0->String); + wideStrLen = mbstowcs(NULL, i0->String, charStrLen); + if(wideStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + if (wideStrLen >= i1->Integer) + { + tree->Alloc = 0; + tree->String = i0->String; + } + else + { + if (i1->Integer - wideStrLen + charStrLen >= 64) + { + tree->Alloc = 1; + tree->String = (char*) nmSysMalloc(i1->Integer - wideStrLen + charStrLen + 1); + } + else + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + sprintf(tree->String, "%*.*s", i1->Integer, i1->Integer, i0->String); + } + return 0; + +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } +/** escape(string, escchars, badchars) **/ +int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + + /** Variables **/ + int escCharLen, badCharLen, numEscapees = 0, i, j, strLen, readPos, insertPos; + wchar_t current; + mbstate_t state; + char * output, * esc, * bad; + size_t charLen, badStrLen, escStrLen; + + tree->DataType = DATA_T_STRING; + if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) + { + mssError(1, "EXP", "escape() requires two or three string parameters"); + return -1; + } + if (i2 && i2->DataType != DATA_T_STRING) { + mssError(1, "EXP", "the optional third escape() parameter must be a string"); + bad = (i2->Flags & EXPR_F_NULL) ? "": i2->String; + return -1; + } + if ((i0->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + return 0; + } + if (i1->Flags & EXPR_F_NULL) + esc = ""; + else + esc = i1->String; + if (tree->Alloc && tree->String) nmSysFree(tree->String); + + /** The esc and bad parameters in wchar_t form **/ + strLen = strlen(i0->String); + escCharLen = strlen(esc); + badCharLen = strlen(bad); + wchar_t escBuf[escCharLen + 2], badBuf[badCharLen + 1]; + escStrLen = mbstowcs(escBuf, esc, escCharLen + 1); + if(escStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + escBuf[escStrLen] = '\\'; + escBuf[++escStrLen] = '\0'; + badStrLen = mbstowcs(badBuf, bad, badCharLen + 1); + if(badStrLen == (size_t)-1) + goto errorInvalidUTF8Char; + + /** Scan through to find all chars to escape **/ + memset(&state, '\0', sizeof(state)); + for(i = 0; i0->String[i] != '\0';) + { + charLen = mbrtowc(¤t, i0->String + i, strLen - i, &state); + if(charLen == (size_t)-1 || charLen == (size_t)-2) + { + goto errorInvalidUTF8Char; + } + i += charLen; + for(j = 0; j < badStrLen; j++) + { + if(current == badBuf[j]) + { + goto errorInvalidChar; + } + } + for(j = 0; j < escStrLen; j++) + { + if(current == escBuf[j]) + { + numEscapees++; + break; + } + } + } + if(numEscapees == 0) + { + tree->Alloc = 0; + tree->String = i0->String; + return 0; + } + + memset(&state, '\0', sizeof(state)); + if(numEscapees + strLen <= 63) + { + output = tree->Types.StringBuf; + tree->Alloc = 0; + } + else + { + output = nmSysMalloc(numEscapees + strLen + 1); + tree->Alloc = 1; + } + for(readPos = 0, insertPos = 0; readPos < strLen;) + { + charLen = mbrtowc(¤t, i0->String + readPos, strLen - readPos, &state); + for(j = 0; j < escStrLen; j++) + { + if(current == escBuf[j]) + { + output[insertPos] = '\\'; + insertPos++; + break; + } + } + while(charLen--) + { + output[insertPos++] = i0->String[readPos++]; + } + } + output[numEscapees + strLen] = '\0'; + + tree->String = output; return 0; + + /** Different types of errors **/ +errorInvalidChar: + mssError(1, "EXP", "WARNING!! String contains invalid character asc=%d", (int) (current)); + return -1; +errorInvalidUTF8Char: + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; } + +int +exp_internal_DefineFunctions() { + + /** Function list for EXPR_N_FUNCTION nodes **/ + xhAdd(&EXP.Functions, "getdate", (char*) exp_fn_getdate); + xhAdd(&EXP.Functions, "user_name", (char*) exp_fn_user_name); + xhAdd(&EXP.Functions, "convert", (char*) exp_fn_convert); + xhAdd(&EXP.Functions, "wordify", (char*) exp_fn_wordify); + xhAdd(&EXP.Functions, "abs", (char*) exp_fn_abs); + xhAdd(&EXP.Functions, "condition", (char*) exp_fn_condition); + xhAdd(&EXP.Functions, "datepart", (char*) exp_fn_datepart); + xhAdd(&EXP.Functions, "isnull", (char*) exp_fn_isnull); + xhAdd(&EXP.Functions, "ltrim", (char*) exp_fn_ltrim); + xhAdd(&EXP.Functions, "lztrim", (char*) exp_fn_lztrim); + xhAdd(&EXP.Functions, "rtrim", (char*) exp_fn_rtrim); + xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); + xhAdd(&EXP.Functions, "replicate", (char*) exp_fn_replicate); + xhAdd(&EXP.Functions, "quote", (char*) exp_fn_quote); + xhAdd(&EXP.Functions, "eval", (char*) exp_fn_eval); + xhAdd(&EXP.Functions, "round", (char*) exp_fn_round); + xhAdd(&EXP.Functions, "dateadd", (char*) exp_fn_dateadd); + xhAdd(&EXP.Functions, "truncate", (char*) exp_fn_truncate); + xhAdd(&EXP.Functions, "constrain", (char*) exp_fn_constrain); + xhAdd(&EXP.Functions, "sin", (char*) exp_fn_sin); + xhAdd(&EXP.Functions, "cos", (char*) exp_fn_cos); + xhAdd(&EXP.Functions, "tan", (char*) exp_fn_tan); + xhAdd(&EXP.Functions, "asin", (char*) exp_fn_asin); + xhAdd(&EXP.Functions, "acos", (char*) exp_fn_acos); + xhAdd(&EXP.Functions, "atan", (char*) exp_fn_atan); + xhAdd(&EXP.Functions, "atan2", (char*) exp_fn_atan2); + xhAdd(&EXP.Functions, "sqrt", (char*) exp_fn_sqrt); + xhAdd(&EXP.Functions, "square", (char*) exp_fn_square); + xhAdd(&EXP.Functions, "degrees", (char*) exp_fn_degrees); + xhAdd(&EXP.Functions, "radians", (char*) exp_fn_radians); + + xhAdd(&EXP.Functions, "count", (char*) exp_fn_count); + xhAdd(&EXP.Functions, "avg", (char*) exp_fn_avg); + xhAdd(&EXP.Functions, "sum", (char*) exp_fn_sum); + xhAdd(&EXP.Functions, "max", (char*) exp_fn_max); + xhAdd(&EXP.Functions, "min", (char*) exp_fn_min); + xhAdd(&EXP.Functions, "first", (char*) exp_fn_first); + xhAdd(&EXP.Functions, "last", (char*) exp_fn_last); + + /** Reverse functions **/ + xhAdd(&EXP.ReverseFunctions, "isnull", (char*) exp_fn_reverse_isnull); + + /** UTF-8/ASCII dependent **/ + if (CxGlobals.CharacterMode == CharModeSigleByte) { + xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_ascii); + xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_charindex); + xhAdd(&EXP.Functions, "upper", (char*) exp_fn_upper); + xhAdd(&EXP.Functions, "lower", (char*) exp_fn_lower); + xhAdd(&EXP.Functions, "char_length", (char*) exp_fn_char_length); + xhAdd(&EXP.Functions, "right", (char*) exp_fn_right); + xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_ralign); + xhAdd(&EXP.Functions, "escape", (char*) exp_fn_escape); + } else { + xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_utf8_ascii); + xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_utf8_charindex); + xhAdd(&EXP.Functions, "upper", (char*) exp_fn_utf8_upper); + xhAdd(&EXP.Functions, "lower", (char*) exp_fn_utf8_lower); + xhAdd(&EXP.Functions, "char_length", (char*) exp_fn_utf8_char_length); + xhAdd(&EXP.Functions, "right", (char*) exp_fn_utf8_right); + xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); + xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); + } + + return 0; +} From bd744087972ba4e7d463f77d12455fa4cb8baee6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 29 Jun 2011 11:49:30 -0600 Subject: [PATCH 004/124] Added function stSeparate to Centrallix's stParse This update added stSeparate for pStructInf files so one can pull out a specific subtree so that it is not freed along with the rest of the tree. --- centrallix/include/stparse.h | 8 +++++++ centrallix/utility/stparse.c | 44 ++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 19 deletions(-) mode change 100644 => 100755 centrallix/include/stparse.h mode change 100644 => 100755 centrallix/utility/stparse.c diff --git a/centrallix/include/stparse.h b/centrallix/include/stparse.h old mode 100644 new mode 100755 index da2af9ae3..2365b4e2b --- a/centrallix/include/stparse.h +++ b/centrallix/include/stparse.h @@ -176,6 +176,14 @@ int stSetAttrValue(pStructInf this, int type, pObjData value, int nval); pExpression stGetExpression(pStructInf this, int nval); void* stGetValueList(pStructInf this, int type, unsigned int* nval); int stAttrIsList(pStructInf this); +/** \brief Separate a subtree from its parent. + + After calling this, you are responsible to free both this subtree + and its parent if there is one. + \param toSeparate The tree to separate from its parent, i f it has one. + \return This returns 0 in all cases. + */ +int stSeparate(pStructInf toSeparate); #endif /* _STPARSE_H */ diff --git a/centrallix/utility/stparse.c b/centrallix/utility/stparse.c old mode 100644 new mode 100755 index 29e837077..a2fbd7477 --- a/centrallix/utility/stparse.c +++ b/centrallix/utility/stparse.c @@ -239,14 +239,35 @@ stAllocInf() return this; } +int stSeparate(pStructInf this){ + int i,j; + + /** Disconnect from parent if there is one. **/ + if (this->Parent) + { + ASSERTMAGIC(this->Parent,MGK_STRUCTINF); + for(i=0;iParent->nSubInf;i++) + { + if (this == this->Parent->SubInf[i]) + { + this->Parent->nSubInf--; + for(j=i;jParent->nSubInf;j++) + { + this->Parent->SubInf[j] = this->Parent->SubInf[j+1]; + } + this->Parent->SubInf[this->Parent->nSubInf] = NULL; + } + } + } + return 0; +} /*** stFreeInf - release an existing StructInf, and any sub infs ***/ int stFreeInf(pStructInf this) { - int i,j; - + int i; ASSERTMAGIC(this,MGK_STRUCTINF); /** Free any subinfs first **/ @@ -263,23 +284,8 @@ stFreeInf(pStructInf this) if (this->Value) expFreeExpression(this->Value); /** Disconnect from parent if there is one. **/ - if (this->Parent) - { - ASSERTMAGIC(this->Parent,MGK_STRUCTINF); - for(i=0;iParent->nSubInf;i++) - { - if (this == this->Parent->SubInf[i]) - { - this->Parent->nSubInf--; - for(j=i;jParent->nSubInf;j++) - { - this->Parent->SubInf[j] = this->Parent->SubInf[j+1]; - } - this->Parent->SubInf[this->Parent->nSubInf] = NULL; - } - } - } - + stSeparate(this); + /** Free the current one. **/ nmFree(this,sizeof(StructInf)); From 3847811ad2c7fee49b9214bd85dbf81b7e5d1ee8 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 29 Jun 2011 11:52:09 -0600 Subject: [PATCH 005/124] Loading of charsetmap.cfg files Added functionality to load a charsetmap file so that charsets can be added to the system so that a system administrator can define the equivalent charset names for their system charset. --- centrallix/centrallix.c | 43 ++++++++++++++++++++++++--- centrallix/etc/INSTALL.txt | 12 ++++++++ centrallix/etc/centrallix.conf.in | 2 +- centrallix/expression/exp_functions.c | 16 +++++++--- centrallix/include/centrallix.h | 14 +++++---- 5 files changed, 72 insertions(+), 15 deletions(-) mode change 100644 => 100755 centrallix/centrallix.c mode change 100644 => 100755 centrallix/etc/INSTALL.txt mode change 100644 => 100755 centrallix/etc/centrallix.conf.in mode change 100644 => 100755 centrallix/include/centrallix.h diff --git a/centrallix/centrallix.c b/centrallix/centrallix.c old mode 100644 new mode 100755 index e979f79b7..cc09f5c4d --- a/centrallix/centrallix.c +++ b/centrallix/centrallix.c @@ -663,7 +663,10 @@ int cxInitialize(void* v) { pFile cxconf; + pFile cxcharsetmap; pStructInf mss_conf; + pStructInf thisCharsetPtr; + char* charsetmapFileName; char* authmethod; char* authmethodfile; char* logmethod; @@ -680,14 +683,13 @@ cxInitialize(void* v) /** Check if UTF-8 or single byte encoding **/ if(MB_CUR_MAX == 1) - CxGlobals.CharacterMode = CharModeSigleByte; + CxGlobals.CharacterMode = CharModeSingleByte; else if(strcmp(nl_langinfo(CODESET), "UTF-8") == 0) CxGlobals.CharacterMode = CharModeUTF8; else { - fprintf(stderr, "Current locale is not single byte encoding or" - "UTF-8! Using C locale.\n"); - setlocale(LC_CTYPE, "C"); + fprintf(stderr, "Current locale is not single byte encoding or UTF-8! Using C locale.\n"); + setlocale(LC_CTYPE, "C"); } /** set up the interrupt handler so we can shutdown properly **/ @@ -719,6 +721,39 @@ cxInitialize(void* v) } fdClose(cxconf, 0); + /** Load the charsetmap file **/ + if(stAttrValue(stLookup(CxGlobals.ParsedConfig, "charsetmap_file"), NULL, &charsetmapFileName, 0) != 0){ + printf("centrallix: did not find required key 'charsetmap_file' in config file '%s'\n", CxGlobals.ConfigFileName); + thExit(); + } + printf("UTF-8TestDebug Charsetmap File: %s\n", charsetmapFileName); + cxcharsetmap = fdOpen(charsetmapFileName, O_RDONLY, 0600); + if(!cxcharsetmap){ + printf("centrallix: could not open charsetmap file '%s'\n", charsetmapFileName); + thExit(); + } + CxGlobals.CharsetMap = stParseMsg(cxcharsetmap, 0); + if (!CxGlobals.CharsetMap) + { + printf("centrallix: error parsing charsetmap file '%s'\n", charsetmapFileName); + thExit(); + } + fdClose(cxcharsetmap, 0); + + /** Now pull out the current charset and free the + rest **/ + if(thisCharsetPtr = stLookup(CxGlobals.CharsetMap, nl_langinfo(CODESET))){ + stSeparate(thisCharsetPtr); + stFreeInf(CxGlobals.CharsetMap); + CxGlobals.CharsetMap = thisCharsetPtr; + + } + else{ + printf("centrallix: could not find current charset '%s' in '%s'\n", nl_langinfo(CODESET), charsetmapFileName); + thExit(); + } + + /** This setting can be dangerous apart from the RBAC security subsystem. ** We default to Enabled here, but this is turned off in the default config. **/ diff --git a/centrallix/etc/INSTALL.txt b/centrallix/etc/INSTALL.txt old mode 100644 new mode 100755 index 52e23d9f1..11eefc9f6 --- a/centrallix/etc/INSTALL.txt +++ b/centrallix/etc/INSTALL.txt @@ -50,3 +50,15 @@ types.cfg: can be changed by changing the "types_config" attribute in the main config file centrallix.conf. +charsetmap.cfg + + In the POSIX specifications, MySQL, and the other components that are being + used in Centrallix, character encodings are specified by strings. This + makes sense for most applications (Like centrallix) where a variable number + of locales could be used, but because the different components refer to the + character sets with different names, it can be very hard to coordinate the + character encoding between all parts of an application. The charsetmap.cfg + file is meant to fix this problem by mapping what the system calls an + encoding to what all the other components call that encoding. See the + default charsetmap.cfg for an example of what it should look like and the + different tags that are currently recognized by Centrallix and its plugins. diff --git a/centrallix/etc/centrallix.conf.in b/centrallix/etc/centrallix.conf.in old mode 100644 new mode 100755 index c5733b081..d763aee74 --- a/centrallix/etc/centrallix.conf.in +++ b/centrallix/etc/centrallix.conf.in @@ -11,7 +11,7 @@ centrallix "system/config" useragent_config = "##SYSCONFDIR##/centrallix/useragent.cfg"; rootnode_type = "system/uxfile"; rootnode_file = "##SYSCONFDIR##/centrallix/rootnode"; - charsetmap_file = "##SYSCONFDIR##/centrallix/charsetmap.cfg" + charsetmap_file = "##SYSCONFDIR##/centrallix/charsetmap.cfg"; iface_dir = "/sys/ifc"; // this is an OSML path theme_dir = "/sys/themes"; // OSML path transaction_log_file = "/var/log/cx_transaction_log"; diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 4858128df..2e3b1b4c5 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "obj.h" #include "cxlib/mtask.h" #include "cxlib/xarray.h" @@ -13,6 +15,7 @@ #include "cxlib/mtlexer.h" #include "expression.h" #include "cxlib/mtsession.h" +#include "centrallix.h" /************************************************************************/ /* Centrallix Application Server System */ @@ -2786,7 +2789,9 @@ exp_internal_DefineFunctions() { xhAdd(&EXP.ReverseFunctions, "isnull", (char*) exp_fn_reverse_isnull); /** UTF-8/ASCII dependent **/ - if (CxGlobals.CharacterMode == CharModeSigleByte) { + if (CxGlobals.CharacterMode == CharModeSingleByte) + { + fprintf(stderr, "UTF-8TestDebug - Launching in single byte char mode!\n"); xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_ascii); xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_charindex); xhAdd(&EXP.Functions, "upper", (char*) exp_fn_upper); @@ -2795,7 +2800,10 @@ exp_internal_DefineFunctions() { xhAdd(&EXP.Functions, "right", (char*) exp_fn_right); xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_escape); - } else { + } + else + { + fprintf(stderr, "UTF-8TestDebug - Launching in UTF-8 mode!\n"); xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_utf8_ascii); xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_utf8_charindex); xhAdd(&EXP.Functions, "upper", (char*) exp_fn_utf8_upper); @@ -2804,7 +2812,7 @@ exp_internal_DefineFunctions() { xhAdd(&EXP.Functions, "right", (char*) exp_fn_utf8_right); xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); - } + } return 0; -} + } diff --git a/centrallix/include/centrallix.h b/centrallix/include/centrallix.h old mode 100644 new mode 100755 index 7c141dbe4..21c4bccb4 --- a/centrallix/include/centrallix.h +++ b/centrallix/include/centrallix.h @@ -19,10 +19,12 @@ typedef char CXCHAR; #define CX_CONV64(x) ((CX_CONV32((x)&0xffffffffLL)<<32)|CX_CONV32(((x)>>32)&0xffffffffLL)) /** Different types of character modes that Centrallix supports. **/ -typedef enum{ - CharModeUTF8, /*** For when the locale supports UTF-8 **/ - CharModeSigleByte /** For when the locale is using a single byte encoding. **/ -} CharMode; +typedef enum + { + CharModeUTF8, /* For when the locale supports UTF-8 */ + CharModeSingleByte /* For when the locale is using a single byte encoding. */ + } + CharMode; /*** Loaded module info ***/ typedef struct _CXM @@ -56,8 +58,8 @@ typedef struct _CXG pCxModule ModuleList; XArray ShutdownHandlers; int Flags; - CharMode CharacterMode; /* This and down deal with charsets */ - pStruct CharsetMap; /* This is the contents of the charset.cfg file */ + CharMode CharacterMode; /* This and CharsetMap deal with charsets */ + pStructInf CharsetMap; /* This is the contents of the charset.cfg file */ /* for looking up equivalent character sets. */ } CxGlobals_t, *pCxGlobals_t; From 1eba9d23bc27f6b97027d558b2f9c987d4a227e4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 29 Jun 2011 12:03:10 -0600 Subject: [PATCH 006/124] Adding charsetmap.cfg file referenced earlier This adds a basic charsetmap.cfg file with a lot of comments. --- centrallix/etc/charsetmap.cfg | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 centrallix/etc/charsetmap.cfg diff --git a/centrallix/etc/charsetmap.cfg b/centrallix/etc/charsetmap.cfg new file mode 100755 index 000000000..614a32af6 --- /dev/null +++ b/centrallix/etc/charsetmap.cfg @@ -0,0 +1,26 @@ +$Version=2$ + +// This file is used for storing equivalency mappings between the system's names +// for a character set and different ways of specifying the same character set +// for different components of Centrallix. +charsetmap "system/charsetmap" + { + + // This level contains nodes that have the name of specific charsets as + // returned by nl_langinfo() + "UTF-8" "system/charsetmap" + { + // The MySQL module looks for this tag to find what it calls the + // the character encoding tha the system calls UTF-8 + mysql = "utf8"; + + // Other allowed tags here are + // http - This is the character encoding that is put into the HTTP + // header when transferring files to the clients. + // If a module is expecting a charset to be mapped here, and it is not + // the module should try to use charset's system name (the name of the + // parent of one of these sectons) or quit. + } + + } + From ca6a1329714daec699872d0b5c13ddec9afc3419 Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Wed, 29 Jun 2011 03:18:58 -0400 Subject: [PATCH 007/124] Added HTTP stating of content charset type. Also added a new utility module with the prefix chr. The header is utility/charsets.h and it contains a function for looking up the charset to be used by a module and some macros to specify attribute names that are allowed in charsetmap.cfg. Added one other macro to define the key in centrallix.conf that specifies the charsetmap file. --- centrallix-sysdoc/Prefixes.txt | 1 + centrallix/Makefile.in | 3 +- centrallix/centrallix.c | 8 ++-- centrallix/etc/charsetmap.cfg | 10 +++-- centrallix/include/charsets.h | 70 ++++++++++++++++++++++++++++++++ centrallix/netdrivers/net_http.c | 5 ++- centrallix/netdrivers/net_http.h | 1 + centrallix/utility/charsets.c | 53 ++++++++++++++++++++++++ 8 files changed, 143 insertions(+), 8 deletions(-) mode change 100644 => 100755 centrallix-sysdoc/Prefixes.txt mode change 100644 => 100755 centrallix/Makefile.in create mode 100755 centrallix/include/charsets.h mode change 100644 => 100755 centrallix/netdrivers/net_http.c mode change 100644 => 100755 centrallix/netdrivers/net_http.h create mode 100755 centrallix/utility/charsets.c diff --git a/centrallix-sysdoc/Prefixes.txt b/centrallix-sysdoc/Prefixes.txt old mode 100644 new mode 100755 index 87d08df4d..08ca22561 --- a/centrallix-sysdoc/Prefixes.txt +++ b/centrallix-sysdoc/Prefixes.txt @@ -2,6 +2,7 @@ CODE MODULE ======= ===================================================================== aud OSDriver - Linux OSS /dev/dsp audio (plays WAV files on ExecMethod) bar BarCode generator module (for prt mgmt) +chr Character set utilities dat OSDriver - Flat data file (CSV/etc) ev MTASK internal - event handling exp Expression compiler/parser/evaluator diff --git a/centrallix/Makefile.in b/centrallix/Makefile.in old mode 100644 new mode 100755 index 33a7a24cb..71cead003 --- a/centrallix/Makefile.in +++ b/centrallix/Makefile.in @@ -66,7 +66,8 @@ XSUPPORT=stparse.o \ mime/mime_encode.o \ mime/mime_util.o \ ptod.o \ - iface.o + iface.o \ + charsets.o SUPPORT=$(patsubst %,utility/%,$(XSUPPORT)) diff --git a/centrallix/centrallix.c b/centrallix/centrallix.c index cc09f5c4d..46c991d0b 100755 --- a/centrallix/centrallix.c +++ b/centrallix/centrallix.c @@ -23,6 +23,7 @@ #include "wgtr.h" #include "iface.h" #include "cxss/cxss.h" +#include "charsets.h" /************************************************************************/ /* Centrallix Application Server System */ @@ -722,8 +723,8 @@ cxInitialize(void* v) fdClose(cxconf, 0); /** Load the charsetmap file **/ - if(stAttrValue(stLookup(CxGlobals.ParsedConfig, "charsetmap_file"), NULL, &charsetmapFileName, 0) != 0){ - printf("centrallix: did not find required key 'charsetmap_file' in config file '%s'\n", CxGlobals.ConfigFileName); + if(stAttrValue(stLookup(CxGlobals.ParsedConfig, CHR_CHARSETMAP_FILE_KEY), NULL, &charsetmapFileName, 0) != 0){ + printf("centrallix: did not find required key '%s' in config file '%s'\n", CHR_CHARSETMAP_FILE_KEY, CxGlobals.ConfigFileName); thExit(); } printf("UTF-8TestDebug Charsetmap File: %s\n", charsetmapFileName); @@ -742,7 +743,8 @@ cxInitialize(void* v) /** Now pull out the current charset and free the rest **/ - if(thisCharsetPtr = stLookup(CxGlobals.CharsetMap, nl_langinfo(CODESET))){ + thisCharsetPtr = stLookup(CxGlobals.CharsetMap, nl_langinfo(CODESET)); + if(thisCharsetPtr){ stSeparate(thisCharsetPtr); stFreeInf(CxGlobals.CharsetMap); CxGlobals.CharsetMap = thisCharsetPtr; diff --git a/centrallix/etc/charsetmap.cfg b/centrallix/etc/charsetmap.cfg index 614a32af6..acb607c4d 100755 --- a/centrallix/etc/charsetmap.cfg +++ b/centrallix/etc/charsetmap.cfg @@ -14,9 +14,13 @@ charsetmap "system/charsetmap" // the character encoding tha the system calls UTF-8 mysql = "utf8"; - // Other allowed tags here are - // http - This is the character encoding that is put into the HTTP - // header when transferring files to the clients. + // The other tags that are allowed at this level are listed in + // include/charsets.h in Centrallix's source. A (hopefully) complete + // list of them is as follows: + // http - The page encoding that is used for this system character + // set. + // sybase - This sets the character set name for the sybase database + // driver. // If a module is expecting a charset to be mapped here, and it is not // the module should try to use charset's system name (the name of the // parent of one of these sectons) or quit. diff --git a/centrallix/include/charsets.h b/centrallix/include/charsets.h new file mode 100755 index 000000000..8accc3be8 --- /dev/null +++ b/centrallix/include/charsets.h @@ -0,0 +1,70 @@ +#ifndef _CHARSETS_H +#define _CHARSETS_H + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2001 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: charsets.c, charsets.h */ +/* Author: Daniel Rothfus */ +/* Creation: June 29, 2011 */ +/* Description: This module provides utilities for working with the */ +/* variable character set support built into Centrallix. */ +/************************************************************************/ + +/** \defgroup charset Character Set Utilities + \brief This module provides utilities for handling the different character + set support implemented in Centrallix. + /{ */ + +/** \defgroup charset_predefs Predefined Keys for Modules + \brief A collection of macros that define string constants that are to be + valid lookup keys in charsetmap.cfg + \{ */ + +/** \brief The string constant for the HTTP generation module. */ +#define CHR_MODULE_HTTP "http" +/** \brief The string constant for the MySQL database driver. */ +#define CHR_MODULE_MYSQL "mysql" +/** \brief A string constant for the Sybase database driver. */ +#define CHR_MODULE_SYBASE "sybase" + +/** \} */ + +/** \brief This is the key in centrallix.conf that specifies the charsetmap.cfg + file */ +#define CHR_CHARSETMAP_FILE_KEY "charsetmap_file" + +/** \brief Check for an equivalent name for the current character set. + + (See charsetmap.cfg for an introduction to equivalent names.) + \param name The name of the module/subsystem/library that needs a name for the + current character set. + \return This returns a pointer to the name of the charset. This should never + return NULL, though it may return an incorrect string if the application is + configured incorrectly. */ +char* chrGetEquivalentName(char* name); + +/** /} */ + +#endif diff --git a/centrallix/netdrivers/net_http.c b/centrallix/netdrivers/net_http.c old mode 100644 new mode 100755 index 063420ee6..f5e8458ae --- a/centrallix/netdrivers/net_http.c +++ b/centrallix/netdrivers/net_http.c @@ -1451,7 +1451,10 @@ nht_internal_GET(pNhtConn conn, pStruct url_inf, char* if_modified_since) { fdPrintf(conn->ConnFD,"Content-Encoding: gzip\r\n"); } - fdPrintf(conn->ConnFD,"Content-Type: text/html\r\nPragma: no-cache\r\n\r\n"); + + /** Print encoding type and content type **/ + fdPrintf(conn->ConnFD,"Content-Type: text/html; charset=%s\r\nPragma: no-cache\r\n\r\n", chrGetEquivalentName("http")); + printf("UTF-8TestDebug Equivalent for HTTP is %s\n", chrGetEquivalentName("http")); if(gzip==1) fdSetOptions(conn->ConnFD, FD_UF_GZIP); diff --git a/centrallix/netdrivers/net_http.h b/centrallix/netdrivers/net_http.h old mode 100644 new mode 100755 index 066c42cd7..e12e9471c --- a/centrallix/netdrivers/net_http.h +++ b/centrallix/netdrivers/net_http.h @@ -36,6 +36,7 @@ #include "cxlib/strtcpy.h" #include "cxlib/qprintf.h" #include "cxss/cxss.h" +#include "charsets.h" /************************************************************************/ /* Centrallix Application Server System */ diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c new file mode 100755 index 000000000..a68f4c8e4 --- /dev/null +++ b/centrallix/utility/charsets.c @@ -0,0 +1,53 @@ +#include "charsets.h" +#include "centrallix.h" +#include + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2001 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: charsets.c, charsets.h */ +/* Author: Daniel Rothfus */ +/* Creation: June 29, 2011 */ +/* Description: This module provides utilities for working with the */ +/* variable character set support built into Centrallix. */ +/************************************************************************/ + +char* chrGetEquivalentName(char* name) + { + pStructInf highestCharsetNode; + char * charsetValue; + + // Try to find the requested attribute + highestCharsetNode = stLookup(CxGlobals.CharsetMap, name); + if(highestCharsetNode) + { + stAttrValue(highestCharsetNode, NULL, &charsetValue, 0); + return charsetValue; + } + else + { + // If not, return the system's name for the charset. + return nl_langinfo(CODESET); + } + } From a3d634a8ad9ed1ce851f7ef98992c88ca84e4141 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 Jul 2011 12:03:56 -0400 Subject: [PATCH 008/124] Adding JavaScript support for UTF-8 Changed some JavaScript files that add UTF-8 suppot to server. --- centrallix-os/sys/js/ht_utils_string.js | 2 +- centrallix-os/sys/js/htdrv_editbox.js | 4 ++-- centrallix-os/sys/js/htdrv_textarea.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/centrallix-os/sys/js/ht_utils_string.js b/centrallix-os/sys/js/ht_utils_string.js index 660953cc5..e46779783 100644 --- a/centrallix-os/sys/js/ht_utils_string.js +++ b/centrallix-os/sys/js/ht_utils_string.js @@ -97,7 +97,7 @@ function tohex16(n) function htutil_escape(s) { - var new_s = String(escape(s)); + var new_s = String(encodeURIComponent(s)); var re = /\//g; var re2 = /\+/g; return new_s.replace(re, "%2f").replace(re2, "%2b"); diff --git a/centrallix-os/sys/js/htdrv_editbox.js b/centrallix-os/sys/js/htdrv_editbox.js index 512c534b2..14213ec6c 100644 --- a/centrallix-os/sys/js/htdrv_editbox.js +++ b/centrallix-os/sys/js/htdrv_editbox.js @@ -366,10 +366,10 @@ function eb_keyhandler(l,e,k) if (l.form) l.form.EscNotify(this); cn_activate(l,'EscapePressed', {}); } - if (k >= 32 && k < 127) + if (k >= 32 && k < 127 || k > 127) { newtxt = cx_hints_checkmodify(l,txt,vistxt.substr(0,l.cursorCol) + String.fromCharCode(k) + vistxt.substr(l.cursorCol,vistxt.length), l._form_type); - if (newtxt != txt) + if (newtxt != txt) { cursoradj = 1; } diff --git a/centrallix-os/sys/js/htdrv_textarea.js b/centrallix-os/sys/js/htdrv_textarea.js index 6cb9086b3..467237411 100644 --- a/centrallix-os/sys/js/htdrv_textarea.js +++ b/centrallix-os/sys/js/htdrv_textarea.js @@ -368,7 +368,7 @@ function tx_keyhandler(l,e,k) if (tx_current.enabled!='full') return 1; if (k != 27 && k != 9 && tx_current.form) tx_current.form.DataNotify(tx_current); - if (k >= 32 && k < 127) + if (k >= 32 && k < 127 || k > 127) { txt = l.rows[l.cursorRow].content; if (l.rows[l.cursorRow+1] && l.cursorCol == l.rows[l.cursorRow].content.length && l.rows[l.cursorRow+1].content[0] != ' ' && k!=32 && !l.rows[l.cursorRow+1].newLine) From 4afdf7a3683510ccc318e56c26e62ba2d7f721cb Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 Jul 2011 12:13:48 -0400 Subject: [PATCH 009/124] Added multiple character set support to MySQL driver --- centrallix/osdrivers/objdrv_mysql.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) mode change 100644 => 100755 centrallix/osdrivers/objdrv_mysql.c diff --git a/centrallix/osdrivers/objdrv_mysql.c b/centrallix/osdrivers/objdrv_mysql.c old mode 100644 new mode 100755 index a65943721..9af05ba78 --- a/centrallix/osdrivers/objdrv_mysql.c +++ b/centrallix/osdrivers/objdrv_mysql.c @@ -15,6 +15,7 @@ #include "cxlib/strtcpy.h" #include "cxlib/qprintf.h" #include "cxlib/util.h" +#include "charsets.h" #include #include @@ -232,6 +233,7 @@ pMysdConn mysd_internal_GetConn(pMysdNode node) { MYSQL_RES * result; + MY_CHARSET_INFO currentCharsetInfo; pMysdConn conn; int i, conn_cnt, found; int min_access; @@ -368,6 +370,26 @@ mysd_internal_GetConn(pMysdNode node) strtcpy(conn->Username, username, sizeof(conn->Username)); strtcpy(conn->Password, password, sizeof(conn->Password)); xaAddItem(&node->Conns, conn); + + printf("UTF-8TestDebug Previous Using character set: %s\n", mysql_character_set_name(&conn->Handle)); + + /** Set up current character set **/ + /** Please note that this assumes that if it is a one byte character encoding, that ASCII will be **/ + /** a valid subset so that the commands still get through OK. **/ + if(mysql_set_character_set(&conn->Handle, chrGetEquivalentName(CHR_MODULE_MYSQL)) != 0) + { + mysql_get_character_set_info(&conn->Handle, ¤tCharsetInfo); + mssError(1, "MYSD", "Could not set character set of MySQL connection to '%s'! Using '%s' instead!", + chrGetEquivalentName(CHR_MODULE_MYSQL), currentCharsetInfo.name); + } + else + { + printf("UTF-8TestDebug Set MySQL Connection charset to %s\n", chrGetEquivalentName(CHR_MODULE_MYSQL)); + } + printf("UTF-8TestDebug After Using character set: %s\n", mysql_character_set_name(&conn->Handle)); + printf("UTF-8TestDebug Extra Query Here! Hehehe Setting status to \xc2\xa9\xc2\xa9\xc2\xa9\xE2\x88\x82\n"); + mysql_query(&conn->Handle, "UPDATE s_user_data SET s_status = '\xc2\xa9\xc2\xa9\xc2\xa9\xE2\x88\x82' WHERE s_username = 'danielrothfus'"); + /** Not quite fatal enough not to return a connection... **/ } /** Make it busy **/ From 58af1ea6fe37fbc67047d42420422232f27627e7 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 Jul 2011 12:33:45 -0400 Subject: [PATCH 010/124] Changed the internals of JavaScript to use (decode|encode)URL Also added a little note in the QPrintf documentation documenting about JSSTR. --- centrallix-os/sys/js/ht_render.js | 2 +- centrallix-os/sys/js/ht_utils_hints.js | 22 +++++++++++----------- centrallix-os/sys/js/htdrv_component.js | 4 ++-- centrallix-os/sys/js/htdrv_dropdown.js | 2 +- centrallix-os/sys/js/htdrv_execmethod.js | 2 +- centrallix-os/sys/js/htdrv_osrc.js | 2 +- centrallix-os/sys/js/htdrv_table.js | 2 +- centrallix-sysdoc/QPrintf.txt | 4 +++- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/centrallix-os/sys/js/ht_render.js b/centrallix-os/sys/js/ht_render.js index 7f2ad8abe..939a5aa38 100644 --- a/centrallix-os/sys/js/ht_render.js +++ b/centrallix-os/sys/js/ht_render.js @@ -400,7 +400,7 @@ function htr_parselinks(lnks) var col = {type:lnk.hash.substr(1), oid:htutil_unpack(lnk.host), hints:lnk.search}; switch(lnk.text.charAt(0)) { - case 'V': col.value = htutil_rtrim(unescape(lnk.text.substr(2))); break; + case 'V': col.value = htutil_rtrim(decodeURIComponent(lnk.text.substr(2))); break; case 'N': col.value = null; break; case 'E': col.value = '** ERROR **'; break; } diff --git a/centrallix-os/sys/js/ht_utils_hints.js b/centrallix-os/sys/js/ht_utils_hints.js index cbd83ea93..28e65464a 100644 --- a/centrallix-os/sys/js/ht_utils_hints.js +++ b/centrallix-os/sys/js/ht_utils_hints.js @@ -244,35 +244,35 @@ function cx_parse_hints(hstr) switch(attrval[0]) { case "d": - ph.DefaultExpr = unescape(attrval[1]); + ph.efaultExpr = decodeURIComponent(attrval[1]); break; case "c": - ph.Constraint = unescape(attrval[1]); + ph.Constraint = decodeURIComponent(attrval[1]); break; case "m": - ph.MinValue = unescape(attrval[1]); + ph.MinValue = decodeURIComponent(attrval[1]); break; case "M": - ph.MaxValue = unescape(attrval[1]); + ph.MaxValue = decodeURIComponent(attrval[1]); break; case "el": ph.EnumList = attrval[1].split(","); for(var j=0; j '' From 2ef09bdc85359fe2fa2b514b3f71625b0264d40c Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 Jul 2011 12:37:03 -0400 Subject: [PATCH 011/124] Re-fixed QPrintf documentation --- centrallix-sysdoc/QPrintf.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/centrallix-sysdoc/QPrintf.txt b/centrallix-sysdoc/QPrintf.txt index 02f16b3e4..ac6714381 100644 --- a/centrallix-sysdoc/QPrintf.txt +++ b/centrallix-sysdoc/QPrintf.txt @@ -112,9 +112,7 @@ FORMATTING... &ESCSP Causes spaces to be escaped with a backslash. &UNESC Causes string to be unescaped (backslashes removed and escaped - values converted to their normal characters). The JavaScript - equivalent is decodeURI and the characters returned by this - should be in UTF-8 encoding. + values converted to their normal characters). &SSYB Causes single quotes in the string to be doubled, sybase quote style ' -> '' From faf809c4d2048b336c5befcfb9f0b585de584df8 Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Thu, 7 Jul 2011 16:19:03 -0400 Subject: [PATCH 012/124] Migrated all multibyte string functionality to chr module Also modified the corresponding functions in exp_functions.c. --- centrallix/expression/exp_functions.c | 472 ++++++----------------- centrallix/include/charsets.h | 154 +++++++- centrallix/utility/charsets.c | 515 ++++++++++++++++++++++++++ 3 files changed, 783 insertions(+), 358 deletions(-) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 2e3b1b4c5..05b59b7cc 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -16,6 +16,7 @@ #include "expression.h" #include "cxlib/mtsession.h" #include "centrallix.h" +#include "charsets.h" /************************************************************************/ /* Centrallix Application Server System */ @@ -2174,8 +2175,7 @@ int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpres int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - wchar_t firstChar; - size_t bytesParsed; + size_t charValue; tree->DataType = DATA_T_INTEGER; if (!i0) @@ -2191,25 +2191,20 @@ int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, p if (i0->String[0] == '\0') tree->Flags |= EXPR_F_NULL; - /** Parse first wide char **/ - bytesParsed = mbrtowc(&firstChar, i0->String, strlen(i0->String), NULL); - if (bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) + charValue = chrGetCharNumber(i0->String); + if (charValue == CHR_INVALID_CHAR) { - goto errorInvalidUTF8Char; + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; } else - tree->Integer = firstChar; + tree->Integer = charValue; return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; } int exp_fn_utf8_charindex(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - char* ptr; - size_t tmpLen; + size_t position; tree->DataType = DATA_T_INTEGER; if (!i0 || !i1) @@ -2227,80 +2222,58 @@ int exp_fn_utf8_charindex(pExpression tree, pParamObjects objlist, pExpression i mssError(1, "EXP", "Two string parameters required for charindex()"); return -1; } - ptr = strstr(i1->String, i0->String); - if (ptr == NULL) - tree->Integer = 0; - else + position = chrSubstringIndex(i1->String, i0->String); + if(position == CHR_INVALID_CHAR) { - tmpLen = mbstowcs(NULL, i1->String, ptr - i1->String) + 1; - if(tmpLen == (size_t)-1) - goto errorInvalidUTF8Char; - tree->Integer = tmpLen; + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; } + else if(position == CHR_NOT_FOUND) + tree->Integer = 0; + else + tree->Integer = position + 1; return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; } int exp_fn_utf8_upper(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int i, oldStrLen, longStrLen, newStrLen; - - tree->DataType = DATA_T_STRING; - if (!i0 || i0->DataType != DATA_T_STRING) - { - mssError(1, "EXP", "One string parameter required for upper()"); - return -1; - } - if (i0->Flags & EXPR_F_NULL) + char * result; + size_t bufferLength = 64; + + tree->DataType = DATA_T_STRING; + if (!i0 || i0->DataType != DATA_T_STRING) { - tree->Flags |= EXPR_F_NULL; - return 0; - } - oldStrLen = strlen(i0->String); - wchar_t longBuffer[oldStrLen + 1]; - longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - for (i = 0; i < oldStrLen + 1; i++) - { - longBuffer[i] = towupper(longBuffer[i]); + mssError(1, "EXP", "One string parameter required for upper()"); + return -1; } - newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); - if(newStrLen == (size_t)-1) - goto errorCharacterConversion; - if (tree->Alloc && tree->String) + if (i0->Flags & EXPR_F_NULL) { - nmSysFree(tree->String); - tree->Alloc = 0; + tree->Flags |= EXPR_F_NULL; + return 0; } - if (newStrLen < 63) + if (tree->Alloc && tree->String) + nmSysFree(tree->String); + + /** Get the lower case string **/ + result = chrToUpper(i0->String, tree->Types.StringBuf, &bufferLength); + + if(result) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; + tree->String = result; + tree->Alloc = bufferLength ? 1 : 0; + return 0; } - else + else { - tree->String = (char*) nmSysMalloc(newStrLen + 1); - tree->Alloc = 1; + mssError(1, "EXP", "String contains invalid UTF-8 character"); /* Also assumed if invalid conversion */ + return -1; } - newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; - -errorCharacterConversion: - mssError(1, "EXP", "Error converting characters"); - return -1; } int exp_fn_utf8_lower(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int i, oldStrLen, longStrLen, newStrLen; + char * result; + size_t bufferLength = 64; tree->DataType = DATA_T_STRING; if (!i0 || i0->DataType != DATA_T_STRING) @@ -2313,44 +2286,25 @@ int exp_fn_utf8_lower(pExpression tree, pParamObjects objlist, pExpression i0, p tree->Flags |= EXPR_F_NULL; return 0; } - oldStrLen = strlen(i0->String); - wchar_t longBuffer[oldStrLen + 1]; - longStrLen = mbstowcs(longBuffer, i0->String, oldStrLen + 1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - for (i = 0; i < oldStrLen + 1; i++) - { - longBuffer[i] = towlower(longBuffer[i]); - } - newStrLen = wcstombs(NULL, longBuffer, oldStrLen + 1); - if(newStrLen == (size_t)-1) - goto errorCharacterConversion; if (tree->Alloc && tree->String) - { nmSysFree(tree->String); - tree->Alloc = 0; - } - if (newStrLen < 63) + + /** Get the lower case string **/ + result = chrToLower(i0->String, tree->Types.StringBuf, &bufferLength); + + if(result) { - tree->String = tree->Types.StringBuf; - tree->Alloc = 0; + tree->String = result; + tree->Alloc = bufferLength ? 1 : 0; + return 0; } - else + else { - tree->String = (char*) nmSysMalloc(newStrLen + 1); - tree->Alloc = 1; + mssError(1, "EXP", "String contains invalid UTF-8 character"); /* Also assumed if invalid conversion */ + return -1; } - newStrLen = wcstombs(tree->String, longBuffer, oldStrLen + 1); - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; - -errorCharacterConversion: - mssError(1, "EXP", "Error converting characters"); - return -1; } + int exp_fn_utf8_char_length(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { @@ -2366,24 +2320,21 @@ int exp_fn_utf8_char_length(pExpression tree, pParamObjects objlist, pExpression mssError(1, "EXP", "One string parameter required for char_length()"); return -1; } - wideLen = mbstowcs(NULL, i0->String, strlen(i0->String) + 1); + + wideLen = chrCharLength(i0->String); + if(wideLen == (size_t)-1) - goto errorInvalidUTF8Char; + { + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } tree->Integer = wideLen; return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; } int exp_fn_utf8_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - int offsetFromEnd, currentPos = 0, numScanned = 0; - size_t charStrLen, longStrLen, step = 0; - mbstate_t currentState; - - memset(¤tState, 0, sizeof(currentState)); + size_t returnCode; if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { @@ -2400,40 +2351,23 @@ int exp_fn_utf8_right(pExpression tree, pParamObjects objlist, pExpression i0, p { nmSysFree(tree->String); } - charStrLen = strlen(i0->String); - longStrLen = mbstowcs(NULL, i0->String, charStrLen+1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - - offsetFromEnd = i1->Integer; - if (offsetFromEnd > longStrLen) offsetFromEnd = longStrLen; - if (offsetFromEnd < 0) offsetFromEnd = 0; - - while(numScanned < (longStrLen - offsetFromEnd)) - { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - break; - numScanned++; - currentPos += step; - } - + tree->DataType = DATA_T_STRING; - tree->String = i0->String + currentPos; tree->Alloc = 0; + tree->String = chrRight(i0->String, i1->Integer < 0 ? 0 : i1->Integer, &returnCode); + if(!tree->String) + { + mssError(1, "EXP", "String contains invalid UTF-8 character"); /* Assumed invalid UTF-8 char */ + return -1; + } return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; } int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - - size_t charStrLen, longStrLen, initial, len; + size_t bufferLength = 64; + size_t initialPosition; + char * output; if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) { @@ -2460,122 +2394,35 @@ int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i } tree->DataType = DATA_T_STRING; - /** String lengths and character lengths and parameters **/ - initial = i0->Integer; - len = i2?i2->Integer:0; - charStrLen = strlen(i0->String); - longStrLen = mbstowcs(NULL, i0->String, charStrLen + 1); - if(longStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - - /** Check range of initial - shortcut if out of bounds **/ - if(initial > longStrLen) + initialPosition = i1->Integer < 1 ? 0 : i1->Integer - 1; + output = chrSubstring(i0->String, initialPosition, i2->Integer < 0 ? 0 : i2->Integer + initialPosition, tree->Types.StringBuf, &bufferLength); + + if(output) { - tree->Alloc = 0; - tree->String = i0->String + charStrLen; + tree->String = output; + tree->Alloc = bufferLength ? 1 : 0; return 0; } - - /** Set length to length of string if too long **/ - if(initial + len - 1 > longStrLen || len <= 0) - len = longStrLen + 1 - initial; - - /** Shortcut for right, returning a pointer inside of the string **/ - if(initial + len - 1 >= longStrLen) - { - /** Variables for right **/ - int currentPos = 0, step = 0, numScanned = 0; - mbstate_t currentState; - - /** Initialize current state **/ - memset(¤tState, 0, sizeof(currentState)); - - /** Scan over to the first char of the right substring to return **/ - while(numScanned < longStrLen - len) - { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - break; - numScanned++; - currentPos += step; - } - - tree->Alloc = 0; - tree->String = i0->String + currentPos; - } - - /** Allocate a separate string and copy data **/ else { - - /** Variables for substring in middle of string **/ - int currentPos = 0, step = 0, numScanned = 0, initialPos, i; - char * newStr; - mbstate_t currentState; - - memset(¤tState, 0, sizeof(currentState)); - - /** Scan to initial position of wanted substring **/ - while(numScanned < initial - 1) - { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - { - tree->Alloc = 0; - tree->String = i0->String + charStrLen; - return 0; - } - numScanned++; - currentPos += step; - } - initialPos = currentPos; - - /** Scan to final position of wanted substring **/ - while(numScanned - initial < len - 1) + if(bufferLength == CHR_MEMORY_OUT) { - step = mbrtowc(NULL, i0->String + currentPos, charStrLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - goto errorInvalidUTF8Char; - if(step == 0) - break; - numScanned++; - currentPos += step; - } - - /** Now initialPos is the first char and finalPos is one after last **/ - if(currentPos - initialPos > 63) - { - tree->Alloc = 0; - newStr = tree->Types.StringBuf; + mssError(1, "EXP", "Memory error!"); + return -1; } else { - tree->Alloc = 1; - newStr = nmSysMalloc(currentPos - initialPos + 1); + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; } - for(i = initialPos; i < currentPos; i++) - { - newStr[i - initialPos] = i0->String[i]; - } - newStr[currentPos - initialPos] = '\0'; - tree->String = newStr; } - - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; } /*** Pad string expression i0 with integer expression i1 number of spaces ***/ int exp_fn_utf8_ralign(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - size_t charStrLen, wideStrLen; + char * returned; + size_t bufferLength = 64; if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_INTEGER) { @@ -2589,48 +2436,30 @@ int exp_fn_utf8_ralign(pExpression tree, pParamObjects objlist, pExpression i0, return 0; } - if (tree->Alloc && tree->String) nmSysFree(tree->String); - charStrLen = strlen(i0->String); - wideStrLen = mbstowcs(NULL, i0->String, charStrLen); - if(wideStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - if (wideStrLen >= i1->Integer) + if (tree->Alloc && tree->String) + nmSysFree(tree->String); + + returned = chrRightAlign(i0->String, i1->Integer, tree->Types.StringBuf, &bufferLength); + + if(returned) { - tree->Alloc = 0; - tree->String = i0->String; + tree->String = returned; + tree->Alloc = bufferLength ? 1 : 0; + return 0; } else { - if (i1->Integer - wideStrLen + charStrLen >= 64) - { - tree->Alloc = 1; - tree->String = (char*) nmSysMalloc(i1->Integer - wideStrLen + charStrLen + 1); - } - else - { - tree->Alloc = 0; - tree->String = tree->Types.StringBuf; - } - sprintf(tree->String, "%*.*s", i1->Integer, i1->Integer, i0->String); - } - return 0; - -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; + } } /** escape(string, escchars, badchars) **/ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - - /** Variables **/ - int escCharLen, badCharLen, numEscapees = 0, i, j, strLen, readPos, insertPos; - wchar_t current; - mbstate_t state; - char * output, * esc, * bad; - size_t charLen, badStrLen, escStrLen; - + char* output, *esc, *bad; + size_t bufferLength = 64; + tree->DataType = DATA_T_STRING; if (!i0 || !i1 || i0->DataType != DATA_T_STRING || i1->DataType != DATA_T_STRING) { @@ -2639,7 +2468,6 @@ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, } if (i2 && i2->DataType != DATA_T_STRING) { mssError(1, "EXP", "the optional third escape() parameter must be a string"); - bad = (i2->Flags & EXPR_F_NULL) ? "": i2->String; return -1; } if ((i0->Flags & EXPR_F_NULL)) @@ -2647,99 +2475,38 @@ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, tree->Flags |= EXPR_F_NULL; return 0; } - if (i1->Flags & EXPR_F_NULL) - esc = ""; - else - esc = i1->String; - if (tree->Alloc && tree->String) nmSysFree(tree->String); - - /** The esc and bad parameters in wchar_t form **/ - strLen = strlen(i0->String); - escCharLen = strlen(esc); - badCharLen = strlen(bad); - wchar_t escBuf[escCharLen + 2], badBuf[badCharLen + 1]; - escStrLen = mbstowcs(escBuf, esc, escCharLen + 1); - if(escStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - escBuf[escStrLen] = '\\'; - escBuf[++escStrLen] = '\0'; - badStrLen = mbstowcs(badBuf, bad, badCharLen + 1); - if(badStrLen == (size_t)-1) - goto errorInvalidUTF8Char; - - /** Scan through to find all chars to escape **/ - memset(&state, '\0', sizeof(state)); - for(i = 0; i0->String[i] != '\0';) - { - charLen = mbrtowc(¤t, i0->String + i, strLen - i, &state); - if(charLen == (size_t)-1 || charLen == (size_t)-2) - { - goto errorInvalidUTF8Char; - } - i += charLen; - for(j = 0; j < badStrLen; j++) - { - if(current == badBuf[j]) - { - goto errorInvalidChar; - } - } - for(j = 0; j < escStrLen; j++) - { - if(current == escBuf[j]) - { - numEscapees++; - break; - } - } - } - if(numEscapees == 0) + if (tree->Alloc && tree->String) { + nmSysFree(tree->String); tree->Alloc = 0; - tree->String = i0->String; - return 0; } + + /** Set the bad and escape strings. */ + esc = i1->Flags & EXPR_F_NULL ? "" : i1->String; + bad = (i2 && !(i2->Flags & EXPR_F_NULL)) ? i2->String : ""; - memset(&state, '\0', sizeof(state)); - if(numEscapees + strLen <= 63) + /** Get the escaped string **/ + output = chrEscape(i0->String, esc, bad, tree->Types.StringBuf, &bufferLength); + + if(output) { - output = tree->Types.StringBuf; - tree->Alloc = 0; + tree->String = output; + tree->Alloc = bufferLength? 1: 0; + return 0; } else { - output = nmSysMalloc(numEscapees + strLen + 1); - tree->Alloc = 1; - } - for(readPos = 0, insertPos = 0; readPos < strLen;) - { - charLen = mbrtowc(¤t, i0->String + readPos, strLen - readPos, &state); - for(j = 0; j < escStrLen; j++) + if(bufferLength == CHR_BAD_CHAR) { - if(current == escBuf[j]) - { - output[insertPos] = '\\'; - insertPos++; - break; - } + mssError(1, "EXP", "WARNING!! String contains invalid character!"); + return -1; } - while(charLen--) + else /* Should be an invalid UTF-8 char */ { - output[insertPos++] = i0->String[readPos++]; + mssError(1, "EXP", "String contains invalid UTF-8 character"); + return -1; } } - output[numEscapees + strLen] = '\0'; - - tree->String = output; - return 0; - - /** Different types of errors **/ -errorInvalidChar: - mssError(1, "EXP", "WARNING!! String contains invalid character asc=%d", (int) (current)); - return -1; -errorInvalidUTF8Char: - mssError(1, "EXP", "String contains invalid UTF-8 character"); - return -1; } int @@ -2757,7 +2524,6 @@ exp_internal_DefineFunctions() { xhAdd(&EXP.Functions, "ltrim", (char*) exp_fn_ltrim); xhAdd(&EXP.Functions, "lztrim", (char*) exp_fn_lztrim); xhAdd(&EXP.Functions, "rtrim", (char*) exp_fn_rtrim); - xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); xhAdd(&EXP.Functions, "replicate", (char*) exp_fn_replicate); xhAdd(&EXP.Functions, "quote", (char*) exp_fn_quote); xhAdd(&EXP.Functions, "eval", (char*) exp_fn_eval); @@ -2792,6 +2558,7 @@ exp_internal_DefineFunctions() { if (CxGlobals.CharacterMode == CharModeSingleByte) { fprintf(stderr, "UTF-8TestDebug - Launching in single byte char mode!\n"); + xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_ascii); xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_charindex); xhAdd(&EXP.Functions, "upper", (char*) exp_fn_upper); @@ -2804,6 +2571,7 @@ exp_internal_DefineFunctions() { else { fprintf(stderr, "UTF-8TestDebug - Launching in UTF-8 mode!\n"); + xhAdd(&EXP.Functions, "substring", (char*) exp_fn_utf8_substring); xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_utf8_ascii); xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_utf8_charindex); xhAdd(&EXP.Functions, "upper", (char*) exp_fn_utf8_upper); diff --git a/centrallix/include/charsets.h b/centrallix/include/charsets.h index 8accc3be8..be3d8a6b4 100755 --- a/centrallix/include/charsets.h +++ b/centrallix/include/charsets.h @@ -1,6 +1,8 @@ #ifndef _CHARSETS_H #define _CHARSETS_H +#include + /************************************************************************/ /* Centrallix Application Server System */ /* Centrallix Core */ @@ -37,9 +39,10 @@ set support implemented in Centrallix. /{ */ -/** \defgroup charset_predefs Predefined Keys for Modules - \brief A collection of macros that define string constants that are to be - valid lookup keys in charsetmap.cfg +/** \defgroup charset_lookups Looking Up Equivalent Character Set Names + \brief This contains a collection of macros that define string constants that + are to be valid lookup keys in charsetmap.cfg and a function to look up their + equivalent values. \{ */ /** \brief The string constant for the HTTP generation module. */ @@ -49,8 +52,6 @@ /** \brief A string constant for the Sybase database driver. */ #define CHR_MODULE_SYBASE "sybase" -/** \} */ - /** \brief This is the key in centrallix.conf that specifies the charsetmap.cfg file */ #define CHR_CHARSETMAP_FILE_KEY "charsetmap_file" @@ -65,6 +66,147 @@ configured incorrectly. */ char* chrGetEquivalentName(char* name); -/** /} */ +/** \} + \defgroup charset_stringfuncs String Functions + \brief These functions operate on multibyte-character strings. (Or single + byte, but they are not as efficient as possible with those.) + + This is a brief note for the calling convention of all of these functions: + If a function returns a size_t, it will either return a valid result or one of + the CHR_* macros on failure. + If a function takes the arguments buffer and bufferLength, these functions will + return a pointer to the resulting character string. The return of these + functions will either be a valid character string or NULL on error. If there + was an error, the bufferLength will be set to the corresponding CHR_* macro + describing the error/problem. If a non-NULL value was returned, the origin of + the buffer can be found by examining the pointer returned and the bufferLength + value after the function is done. If the bufferLength is 0 and the pointer + returned is equal to buffer, the given preallocated buffer was used for the + results. If the bufferLength is 0 and the returned pointer is not buffer, then + the pointer points to some place in the original string, which is only done in + certain circumstances. Otherwise, if the bufferSize is non-zero, the function + had to allocate memory on the heap with nmSysMalloc, so the returned string + will need to be freed. + \todo Make a these functions all work with single byte encodings quickly as + as well? (Add special cases for single byte strings?) + \{ */ + +/** \brief This constant is returned when an invalid UTF-8 character is found + for functions that return type size_t. + + This will also be returned if there was a character set conversion error. */ +#define CHR_INVALID_CHAR (size_t)-2 +/** \brief This constant is returned for searching functions when the desired + character is not found in the chr module. */ +#define CHR_NOT_FOUND (size_t)-1 +/** \brief This is returned when an invalid argument is passed to a function in + the chr module. + + This is used for such things as NULL pointers with required arguments. */ +#define CHR_INVALID_ARGUMENT (size_t)-3 +/** \brief Returned when there is not enough memory to do an operation. */ +#define CHR_MEMORY_OUT (size_t)-4 +/** \brief This is passed when a disallowed (not invalid) character is found + in a string. */ +#define CHR_BAD_CHAR (size_t)-5 + +/** \brief Get the numeric value of a character (possibly multi-byte). + \param character A pointer to the character to analyze. + \return This returns the numeric value of the first character in the string in + character based on the current locale. This could also return an error, such + as CHR_NOT_FOUND or CHR_INVALID_CHAR. (See the extended module description for + more information.) */ +size_t chrGetCharNumber(char* character); + +/** \brief Get a substring of a given string. + \param string The (possibly multibyte) string to find the substring in. + \param begin The character index of the first CHARACTER to start copying at. + \param end The character index of the character (not byte) right after the + substring to find. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the substring or NULL on error. (See the extended + module description for more information.) */ +char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* bufferLength); + +/** \brief Find the first instance of a substring in string. + \param string The string to find the substring in. + \param substring The substring to find in the string. + \return Thist returns the offset into the string that the character was found + at or an error, such as CHR_NOT_FOUND or CHR_INVALID_CHAR. (See the extended + module description for more information.) */ +size_t chrSubstringIndex(char* string, char* substring); + +/** \brief Convert a (possibly multibyte) string to upper case. + \param string The string to convert to upper case. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the upper case string or NULL on error. (See the extended + module description for more information.) */ +char* chrToUpper(char* string, char* buffer, size_t* bufferLength); + +/** \brief Convert a (possibly multibyte) string to lower case. + \param string The string to convert to lower case. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the lower case string or NULL on error. (See the extended + module description for more information.) */ +char* chrToLower(char* string, char* buffer, size_t* bufferLength); + +/** \brief This function returns the number of characters (NOT BYTES) in a + given string. + \param string The string to return the number of characters in. + \return This returns the length or an error such (but not limited to) as + CHR_INVALID_CHAR on error. */ +size_t chrCharLength(char* string); + +/** \brief Get a specific number of the rightmost characters in the string. + + This function always returns an offset into the original string since no + copying is ever needed. + \param string The string to get numChars number of rightmost characters. + \param numChars The number of characters to grab off of the right of the + string. + \param returnCode This takes the role of bufferLength in the other char* + returning functions for return codes. + \return This returns a pointer to the position in the original string where + only the numChar(th) right characters are viewable from. + */ +char* chrRight(char* string, size_t numChars, size_t* returnCode); + +/** \brief Escape certain characters in a string with '\' while banning some. + \param string The string to escape. + \param escape A string with all of the characters to escape. + \param bad The bad characters to stop processing on. When it stops processing, + it returns NULL and sets the value of bufferLength to CHR_BAD_CHAR. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the escaped string which may point to the preallocated + buffer or an allocated buffer or NULL if a bad character was encountered. (See + the extended module description for more information.) */ +char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* bufferLength); + +/** \brief Create a string of a certain minimum size with spaces padding the + string to the right if the string is not long enough. + \param string The string to resize to the minimum given length. + \param minLength The minimum number of characters that you want the string to + take up. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the buffered string or NULL on error. Please note that + this is extremely prone to returning the original string because this is done + whenever the string is the same length or longer than the minLength. (See the + extended module description for more information.) + */ +char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength); + +/** \} */ + +/** \} */ #endif diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c index a68f4c8e4..496c48949 100755 --- a/centrallix/utility/charsets.c +++ b/centrallix/utility/charsets.c @@ -1,6 +1,10 @@ #include "charsets.h" #include "centrallix.h" #include +#include +#include +#include +#include /************************************************************************/ /* Centrallix Application Server System */ @@ -51,3 +55,514 @@ char* chrGetEquivalentName(char* name) return nl_langinfo(CODESET); } } + +/** String Functions Follow **/ +size_t chrGetCharNumber(char* character) + { + size_t bytesParsed; + wchar_t firstChar = 0; + if(!character) + return CHR_INVALID_ARGUMENT; + bytesParsed = mbrtowc(&firstChar, character, strlen(character), NULL); + if(bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) + { + return CHR_INVALID_CHAR; + } + else + { + return (size_t)firstChar; + } + } + +char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* bufferLength) + { + size_t strCharLen, strByteLen, charsScanned = 0, bytesScanned = 0, tmpBytesScanned, bytesInStringScanned = 0; + char* initialPos, *output; + mbstate_t state; + + /** Initialize the multi-byte scanning state **/ + memset(&state, 0, sizeof(state)); + + strByteLen = strlen(string); + strCharLen = mbstowcs(NULL, string, 0); + if(strCharLen == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Bounds checking **/ + if(end > strCharLen) + end = strCharLen; + if(begin > end) + begin = end; + + /** Check if this is to return the entire string. **/ + if(begin == 0 && end == strCharLen){ + *bufferLength = 0; + return string; + } + + /** Check if this is being used as a shortcut for right **/ + if(end == strCharLen){ + return chrRight(string, strCharLen - begin, bufferLength); + } + + /** Find the required number of bytes for the output buffer **/ + /** Scan to the beginning character **/ + while(charsScanned < begin) + { + tmpBytesScanned = mbrtowc(NULL, string + bytesScanned, strByteLen - bytesScanned, &state); + if(tmpBytesScanned == (size_t)-1 || tmpBytesScanned == (size_t)-2) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + bytesScanned += tmpBytesScanned; + charsScanned++; + } + initialPos = string + bytesScanned; + + /** Find ending position **/ + while(charsScanned < end) + { + tmpBytesScanned = mbrtowc(NULL, string + bytesScanned, strByteLen - bytesScanned, &state); + if(tmpBytesScanned == (size_t)-1 || tmpBytesScanned == (size_t)-2) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + bytesScanned += tmpBytesScanned; + bytesInStringScanned += tmpBytesScanned; + charsScanned++; + } + + /** Now chars scanned is the size of the buffer to use **/ + if(buffer && (bytesInStringScanned < *bufferLength)) + { + *bufferLength = 0; + output = buffer; + } + else + { + output = (char *)nmSysMalloc(bytesInStringScanned + 1); + if(!output) + { + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = bytesInStringScanned + 1; + } + + /** Convert the string at initial pos using only so many characters **/ + strncpy(output, initialPos, bytesInStringScanned); + + /** Append null and return **/ + output[bytesInStringScanned] = '\0'; + return output; + } + +size_t chrSubstringIndex(char* string, char* character) + { + char * ptr; + size_t tmpLen; + if(!string || !character) + return CHR_INVALID_ARGUMENT; + ptr = strstr(string, character); + if (ptr == NULL) + { + return CHR_NOT_FOUND; + } + else + { + tmpLen = mbstowcs(NULL, string, 0) - mbstowcs(NULL, ptr, 0); + if(tmpLen == (size_t)-1) + return CHR_INVALID_CHAR; + else + { + return tmpLen; + } + } + } + +char* chrToUpper(char* string, char* buffer, size_t* bufferLength) + { + size_t stringCharLength, currentPos, newStrByteLength; + char* toReturn; + wchar_t* longBuffer; + + /** Check arguments **/ + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + stringCharLength = mbstowcs(NULL, string, 0); + if(stringCharLength == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Create wchar_t buffer */ + longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); + if(!longBuffer){ + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + mbstowcs(longBuffer, string, stringCharLength + 1); + currentPos = stringCharLength; + while(currentPos--) + longBuffer[currentPos] = towupper(longBuffer[currentPos]); + + newStrByteLength = wcstombs(NULL, longBuffer, 0); + if(newStrByteLength == (size_t)-1) + { + nmSysFree(longBuffer); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + if(buffer && (newStrByteLength < *bufferLength)) + { + toReturn = buffer; + *bufferLength = 0; + } + else + { + toReturn = (char *)nmSysMalloc(newStrByteLength + 1); + if(!toReturn) + { + nmSysFree(longBuffer); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = newStrByteLength + 1; + } + + /** Copy over to output buffer **/ + wcstombs(toReturn, longBuffer, newStrByteLength + 1); + nmSysFree(longBuffer); + return toReturn; + } + +char* chrToLower(char* string, char* buffer, size_t* bufferLength) + { + size_t stringCharLength, currentPos, newStrByteLength; + char* toReturn; + wchar_t* longBuffer; + + /** Check arguments **/ + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + stringCharLength = mbstowcs(NULL, string, 0); + if(stringCharLength == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Create wchar_t buffer */ + longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); + if(!longBuffer){ + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + mbstowcs(longBuffer, string, stringCharLength + 1); + currentPos = stringCharLength; + while(currentPos--) + longBuffer[currentPos] = towlower(longBuffer[currentPos]); + + newStrByteLength = wcstombs(NULL, longBuffer, 0); + if(newStrByteLength == (size_t)-1) + { + nmSysFree(longBuffer); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + if(buffer && (newStrByteLength < *bufferLength)) + { + toReturn = buffer; + *bufferLength = 0; + } + else + { + toReturn = (char *)nmSysMalloc(newStrByteLength + 1); + if(!toReturn) + { + nmSysFree(longBuffer); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = newStrByteLength + 1; + } + + /** Copy over to output buffer **/ + wcstombs(toReturn, longBuffer, newStrByteLength + 1); + nmSysFree(longBuffer); + return toReturn; + } + +size_t chrCharLength(char* string) + { + size_t length; + if(!string) + return CHR_INVALID_ARGUMENT; + length = mbstowcs(NULL, string, 0); + if(length == (size_t)-1) + return CHR_INVALID_CHAR; + else + return length; + } + +char* chrRight(char* string, size_t offsetFromEnd, size_t* returnCode) + { + size_t currentPos = 0, numScanned = 0; + size_t strByteLen, strCharLen, step = 0; + mbstate_t currentState; + + /** Clear initial state **/ + memset(¤tState, 0, sizeof(currentState)); + + strByteLen = strlen(string); + strCharLen = mbstowcs(NULL, string, 0); + if(strCharLen == (size_t)-1) + { + *returnCode = CHR_INVALID_CHAR; + return NULL; + } + + /** Boundary checking **/ + if (offsetFromEnd > strCharLen) + offsetFromEnd = strCharLen; + if (offsetFromEnd < 0) + offsetFromEnd = 0; + + /** Scan through until we hit the offset into the string that we need to. **/ + while(numScanned < (strCharLen - offsetFromEnd)) + { + step = mbrtowc(NULL, string + currentPos, strByteLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + { + *returnCode = CHR_INVALID_CHAR; + return NULL; + } + if(step == 0) /* Hit the end of the string unintentionally */ + break; + numScanned++; + currentPos += step; + } + + /** All done - return offset into original string **/ + *returnCode = 0; + return string + currentPos; + } + +char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* bufferLength) + { + wchar_t current, *escBuf, *badBuf; + mbstate_t state; + char * output; + size_t escCharLen, badCharLen, numEscapees = 0, i, j, readPos, insertPos, strByteLen, charLen; + + /** Check parameters **/ + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + /** The esc and bad parameters in wchar_t form **/ + strByteLen = strlen(string); + escCharLen = mbstowcs(NULL, escape, 0); + badCharLen = mbstowcs(NULL, bad, 0); + + /** Declare buffer variables here! **/ + escBuf = nmSysMalloc(sizeof(wchar_t) * (escCharLen + 2)); + if(!escBuf) + { + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + badBuf = nmSysMalloc(sizeof(wchar_t) * (badCharLen + 1)); + if(!badBuf) + { + nmSysFree(escBuf); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + + escCharLen = mbstowcs(escBuf, escape, escCharLen + 1); /* Translate over the escape characters */ + if(escCharLen == (size_t)-1) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + escBuf[escCharLen] = '\\'; /* Add in the / character to those to escape. */ + escBuf[++escCharLen] = '\0'; + + badCharLen = mbstowcs(badBuf, bad, badCharLen + 1); /* Translate over the bad characters */ + if(badCharLen == (size_t)-1) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Clear the current state of the UTF-8 state holder **/ + memset(&state, '\0', sizeof(state)); + + /** Scan through the string **/ + for(i = 0; string[i] != '\0';) + { + charLen = mbrtowc(¤t, string + i, strByteLen - i, &state); + if(charLen == (size_t)-1 || charLen == (size_t)-2) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + i += charLen; + + for(j = 0; j < badCharLen; j++) + { + if(current == badBuf[j]) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_BAD_CHAR; + return NULL; + } + } + for(j = 0; j < escCharLen; j++) + { + if(current == escBuf[j]) + { + numEscapees++; + break; + } + } + } + if(numEscapees == 0) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = 0; + return string; + } + + /** Reinitialize state **/ + memset(&state, '\0', sizeof(state)); + + /** Find the buffer to put the results into **/ + if(buffer && (numEscapees + strByteLen < *bufferLength)) + { + output = buffer; + *bufferLength = 0; + } + else + { + output = nmSysMalloc(numEscapees + strByteLen + 1); + if(!output) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = numEscapees + strByteLen + 1; + } + + /** Insert back slashes **/ + for(readPos = 0, insertPos = 0; readPos < strByteLen;) + { + charLen = mbrtowc(¤t, string + readPos, strByteLen - readPos, &state); + for(j = 0; j < escCharLen; j++) + { + if(current == escBuf[j]) + { + output[insertPos] = '\\'; + insertPos++; + break; + } + } + while(charLen--) + { + output[insertPos++] = string[readPos++]; + } + } + output[numEscapees + strByteLen] = '\0'; /* Cap off with NULL character */ + nmSysFree(escBuf); + nmSysFree(badBuf); + return output; + } + +char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength) + { + size_t stringCharLen, newStrByteLen, c, stringByteLength; + long long numSpaces; + char * toReturn; + + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + /** Calculate the number of spaces to add **/ + stringByteLength = strlen(string); + stringCharLen = mbstowcs(NULL, string, 0); + if(stringCharLen == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + numSpaces = (long long)minLength - stringCharLen; + if(numSpaces <= 0) /* If we do not have to add spaces, return the original string. */ + { + *bufferLength = 0; + return string; + } + + newStrByteLen = numSpaces + stringByteLength; /* The needed number of bytes in the new string */ + + /** Set the string to return. **/ + if(buffer && (newStrByteLen < *bufferLength)) + { + toReturn = buffer; + *bufferLength = 0; + } + else + { + toReturn = nmSysMalloc(newStrByteLen + 1); + if(!toReturn) + { + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = newStrByteLen + 1; + } + + c = numSpaces; + while(c--) + { + toReturn[c] = ' '; + } + c = newStrByteLen; + while(c-- > numSpaces) + { + toReturn[c] = string[c - numSpaces]; + } + toReturn[newStrByteLen] = '\0'; + return toReturn; + } From 6fd75b52274c5236ddbe08b7908fdd144fec009a Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Thu, 7 Jul 2011 16:20:23 -0400 Subject: [PATCH 013/124] Added ASCII to charsetmap --- centrallix/etc/charsetmap.cfg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/centrallix/etc/charsetmap.cfg b/centrallix/etc/charsetmap.cfg index acb607c4d..f643c1c58 100755 --- a/centrallix/etc/charsetmap.cfg +++ b/centrallix/etc/charsetmap.cfg @@ -25,6 +25,10 @@ charsetmap "system/charsetmap" // the module should try to use charset's system name (the name of the // parent of one of these sectons) or quit. } - + "ANSI_X3.4-1968" "system/charsetmap" + { + mysql = "latin1"; + } } + From 74b09ef5bacbf1f193f53b8a20b57ec88b233573 Mon Sep 17 00:00:00 2001 From: Daniel Rothfus Date: Thu, 7 Jul 2011 16:28:15 -0400 Subject: [PATCH 014/124] Getting rid of some UTF-8 based test code --- centrallix/centrallix.c | 1 - centrallix/expression/exp_functions.c | 2 -- centrallix/netdrivers/net_http.c | 1 - centrallix/osdrivers/objdrv_mysql.c | 10 ++-------- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/centrallix/centrallix.c b/centrallix/centrallix.c index 46c991d0b..6dca38b69 100755 --- a/centrallix/centrallix.c +++ b/centrallix/centrallix.c @@ -727,7 +727,6 @@ cxInitialize(void* v) printf("centrallix: did not find required key '%s' in config file '%s'\n", CHR_CHARSETMAP_FILE_KEY, CxGlobals.ConfigFileName); thExit(); } - printf("UTF-8TestDebug Charsetmap File: %s\n", charsetmapFileName); cxcharsetmap = fdOpen(charsetmapFileName, O_RDONLY, 0600); if(!cxcharsetmap){ printf("centrallix: could not open charsetmap file '%s'\n", charsetmapFileName); diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 05b59b7cc..e076af3bd 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -2557,7 +2557,6 @@ exp_internal_DefineFunctions() { /** UTF-8/ASCII dependent **/ if (CxGlobals.CharacterMode == CharModeSingleByte) { - fprintf(stderr, "UTF-8TestDebug - Launching in single byte char mode!\n"); xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_ascii); xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_charindex); @@ -2570,7 +2569,6 @@ exp_internal_DefineFunctions() { } else { - fprintf(stderr, "UTF-8TestDebug - Launching in UTF-8 mode!\n"); xhAdd(&EXP.Functions, "substring", (char*) exp_fn_utf8_substring); xhAdd(&EXP.Functions, "ascii", (char*) exp_fn_utf8_ascii); xhAdd(&EXP.Functions, "charindex", (char*) exp_fn_utf8_charindex); diff --git a/centrallix/netdrivers/net_http.c b/centrallix/netdrivers/net_http.c index f5e8458ae..4ca98abf2 100755 --- a/centrallix/netdrivers/net_http.c +++ b/centrallix/netdrivers/net_http.c @@ -1454,7 +1454,6 @@ nht_internal_GET(pNhtConn conn, pStruct url_inf, char* if_modified_since) /** Print encoding type and content type **/ fdPrintf(conn->ConnFD,"Content-Type: text/html; charset=%s\r\nPragma: no-cache\r\n\r\n", chrGetEquivalentName("http")); - printf("UTF-8TestDebug Equivalent for HTTP is %s\n", chrGetEquivalentName("http")); if(gzip==1) fdSetOptions(conn->ConnFD, FD_UF_GZIP); diff --git a/centrallix/osdrivers/objdrv_mysql.c b/centrallix/osdrivers/objdrv_mysql.c index 9af05ba78..589daf600 100755 --- a/centrallix/osdrivers/objdrv_mysql.c +++ b/centrallix/osdrivers/objdrv_mysql.c @@ -370,9 +370,7 @@ mysd_internal_GetConn(pMysdNode node) strtcpy(conn->Username, username, sizeof(conn->Username)); strtcpy(conn->Password, password, sizeof(conn->Password)); xaAddItem(&node->Conns, conn); - - printf("UTF-8TestDebug Previous Using character set: %s\n", mysql_character_set_name(&conn->Handle)); - + /** Set up current character set **/ /** Please note that this assumes that if it is a one byte character encoding, that ASCII will be **/ /** a valid subset so that the commands still get through OK. **/ @@ -384,12 +382,8 @@ mysd_internal_GetConn(pMysdNode node) } else { - printf("UTF-8TestDebug Set MySQL Connection charset to %s\n", chrGetEquivalentName(CHR_MODULE_MYSQL)); - } - printf("UTF-8TestDebug After Using character set: %s\n", mysql_character_set_name(&conn->Handle)); - printf("UTF-8TestDebug Extra Query Here! Hehehe Setting status to \xc2\xa9\xc2\xa9\xc2\xa9\xE2\x88\x82\n"); - mysql_query(&conn->Handle, "UPDATE s_user_data SET s_status = '\xc2\xa9\xc2\xa9\xc2\xa9\xE2\x88\x82' WHERE s_username = 'danielrothfus'"); /** Not quite fatal enough not to return a connection... **/ + } } /** Make it busy **/ From 04f45d9425af72bfba4231550f048fea8a864eaa Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Fri, 7 Oct 2011 21:40:21 -0600 Subject: [PATCH 015/124] Updating charset map with charset names for MIME/http, sybase, iso-8859-1 --- centrallix/etc/charsetmap.cfg | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/centrallix/etc/charsetmap.cfg b/centrallix/etc/charsetmap.cfg index f643c1c58..6fadd0808 100755 --- a/centrallix/etc/charsetmap.cfg +++ b/centrallix/etc/charsetmap.cfg @@ -5,13 +5,18 @@ $Version=2$ // for different components of Centrallix. charsetmap "system/charsetmap" { - // This level contains nodes that have the name of specific charsets as - // returned by nl_langinfo() + // returned by nl_langinfo(). + // + // See: "man nl_langinfo" and "iconv --list". + // "UTF-8" "system/charsetmap" { // The MySQL module looks for this tag to find what it calls the - // the character encoding tha the system calls UTF-8 + // the character encoding tha the system calls UTF-8. + // + // See: http://dev.mysql.com/doc/refman/5.0/en/charset-charsets.html + // mysql = "utf8"; // The other tags that are allowed at this level are listed in @@ -24,11 +29,31 @@ charsetmap "system/charsetmap" // If a module is expecting a charset to be mapped here, and it is not // the module should try to use charset's system name (the name of the // parent of one of these sectons) or quit. + + // For Sybase (objectsystem driver): + // http://manuals.sybase.com/onlinebooks/group-charc/chg0300e/charsets/@Generic__BookTextView/1706 + // + sybase = "utf8"; + + // For HTTP (both the netdriver and the objectsystem driver) + // http://www.iana.org/assignments/character-sets + // Use "preferred MIME name" charsets for HTTP. + // + http = "utf-8"; } - "ANSI_X3.4-1968" "system/charsetmap" + + "ISO-8859-1" "system/charsetmap" { mysql = "latin1"; + sybase = "iso_1"; + http = "iso-8859-1"; } - } + "ANSI_X3.4-1968" "system/charsetmap" + { + mysql = "ascii"; + sybase = "ascii_8"; + http = "us-ascii"; + } + } From 0ab6724f3da422e5c466d4c19620abb3604112b9 Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Fri, 7 Oct 2011 22:30:06 -0600 Subject: [PATCH 016/124] mbrtowc and mbstowcs return value checks (not all strictly needed; for clarity) --- centrallix/utility/charsets.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c index 496c48949..618205848 100755 --- a/centrallix/utility/charsets.c +++ b/centrallix/utility/charsets.c @@ -165,7 +165,7 @@ char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* size_t chrSubstringIndex(char* string, char* character) { char * ptr; - size_t tmpLen; + size_t tmpLen1, tmpLen2; if(!string || !character) return CHR_INVALID_ARGUMENT; ptr = strstr(string, character); @@ -175,12 +175,13 @@ size_t chrSubstringIndex(char* string, char* character) } else { - tmpLen = mbstowcs(NULL, string, 0) - mbstowcs(NULL, ptr, 0); - if(tmpLen == (size_t)-1) + tmpLen1 = mbstowcs(NULL, string, 0); + tmpLen2 = mbstowcs(NULL, ptr, 0); + if(tmpLen1 == (size_t)-1 || tmpLen2 == (size_t)-1) return CHR_INVALID_CHAR; else { - return tmpLen; + return tmpLen1 - tmpLen2; } } } @@ -382,7 +383,16 @@ char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* buf strByteLen = strlen(string); escCharLen = mbstowcs(NULL, escape, 0); badCharLen = mbstowcs(NULL, bad, 0); - + if (escCharLen == (size_t)-1 || badCharLen == (size_t)-1) + { + /** This is checked below, but we check here for clarity + ** as well as to have the check before we pass the values + ** to nmSysMalloc(). + **/ + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + /** Declare buffer variables here! **/ escBuf = nmSysMalloc(sizeof(wchar_t) * (escCharLen + 2)); if(!escBuf) @@ -487,6 +497,14 @@ char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* buf for(readPos = 0, insertPos = 0; readPos < strByteLen;) { charLen = mbrtowc(¤t, string + readPos, strByteLen - readPos, &state); + if (charLen == (size_t)-1 || charLen == (size_t)-2) + { + /** For clarity **/ + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_BAD_CHAR; + return NULL; + } for(j = 0; j < escCharLen; j++) { if(current == escBuf[j]) From 5549e9f36c807026e59bf936bc9382a36f59f420 Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Fri, 7 Oct 2011 22:43:09 -0600 Subject: [PATCH 017/124] Adding chrValid() and fixing invalid seq check in UTF-8 version of char_length --- centrallix/expression/exp_functions.c | 4 ++-- centrallix/include/charsets.h | 6 ++++++ centrallix/utility/charsets.c | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index e076af3bd..3858352b2 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -2323,7 +2323,7 @@ int exp_fn_utf8_char_length(pExpression tree, pParamObjects objlist, pExpression wideLen = chrCharLength(i0->String); - if(wideLen == (size_t)-1) + if(wideLen == CHR_INVALID_CHAR) { mssError(1, "EXP", "String contains invalid UTF-8 character"); return -1; @@ -2407,7 +2407,7 @@ int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i { if(bufferLength == CHR_MEMORY_OUT) { - mssError(1, "EXP", "Memory error!"); + mssError(1, "EXP", "Memory exhausted!"); return -1; } else diff --git a/centrallix/include/charsets.h b/centrallix/include/charsets.h index be3d8a6b4..a258c7df3 100755 --- a/centrallix/include/charsets.h +++ b/centrallix/include/charsets.h @@ -205,6 +205,12 @@ char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* buf */ char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength); +/** \brief Convenience function for checking the validity of results. + \param result The result value obtained from the string function. + \return Returns 1 if valid, 0 if not valid. + */ +int chrValid(int result); + /** \} */ /** \} */ diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c index 618205848..527c87186 100755 --- a/centrallix/utility/charsets.c +++ b/centrallix/utility/charsets.c @@ -584,3 +584,9 @@ char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* buffer toReturn[newStrByteLen] = '\0'; return toReturn; } + +int chrValid(int result) + { + return !(result == CHR_MEMORY_OUT || result == CHR_BAD_CHAR || result == CHR_INVALID_CHAR || result == CHR_INVALID_ARGUMENT || result == CHR_NOT_FOUND); + } + From 6bf4e367f605447fa665d7d9e3a5cc72993e0db7 Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Fri, 7 Oct 2011 23:01:39 -0600 Subject: [PATCH 018/124] Adding capability for admin to set the locale in the server config. --- centrallix/centrallix.c | 54 ++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/centrallix/centrallix.c b/centrallix/centrallix.c index 6dca38b69..20dbab9b7 100755 --- a/centrallix/centrallix.c +++ b/centrallix/centrallix.c @@ -682,17 +682,6 @@ cxInitialize(void* v) /** Set the current locale to user's locale for chars **/ setlocale(LC_CTYPE, ""); - /** Check if UTF-8 or single byte encoding **/ - if(MB_CUR_MAX == 1) - CxGlobals.CharacterMode = CharModeSingleByte; - else if(strcmp(nl_langinfo(CODESET), "UTF-8") == 0) - CxGlobals.CharacterMode = CharModeUTF8; - else - { - fprintf(stderr, "Current locale is not single byte encoding or UTF-8! Using C locale.\n"); - setlocale(LC_CTYPE, "C"); - } - /** set up the interrupt handler so we can shutdown properly **/ mtAddSignalHandler(SIGINT,cxShutdownThread); @@ -722,37 +711,58 @@ cxInitialize(void* v) } fdClose(cxconf, 0); + /** Force the server locale? **/ + if (stAttrValue(stLookup(CxGlobals.ParsedConfig, "locale"), NULL, &ptr, 0) == 0) + { + if (setlocale(LC_CTYPE, ptr) == NULL) + setlocale(LC_CTYPE, ""); + } + + /** Check if UTF-8 or single byte encoding **/ + if(MB_CUR_MAX == 1) + CxGlobals.CharacterMode = CharModeSingleByte; + else if(strcmp(nl_langinfo(CODESET), "UTF-8") == 0) + CxGlobals.CharacterMode = CharModeUTF8; + else + { + fprintf(stderr, "Current locale is not single byte encoding or UTF-8! Using C locale.\n"); + setlocale(LC_CTYPE, "C"); + } + /** Load the charsetmap file **/ - if(stAttrValue(stLookup(CxGlobals.ParsedConfig, CHR_CHARSETMAP_FILE_KEY), NULL, &charsetmapFileName, 0) != 0){ + if(stAttrValue(stLookup(CxGlobals.ParsedConfig, CHR_CHARSETMAP_FILE_KEY), NULL, &charsetmapFileName, 0) != 0) + { printf("centrallix: did not find required key '%s' in config file '%s'\n", CHR_CHARSETMAP_FILE_KEY, CxGlobals.ConfigFileName); thExit(); - } + } cxcharsetmap = fdOpen(charsetmapFileName, O_RDONLY, 0600); - if(!cxcharsetmap){ + if(!cxcharsetmap) + { printf("centrallix: could not open charsetmap file '%s'\n", charsetmapFileName); thExit(); - } + } CxGlobals.CharsetMap = stParseMsg(cxcharsetmap, 0); if (!CxGlobals.CharsetMap) - { + { printf("centrallix: error parsing charsetmap file '%s'\n", charsetmapFileName); thExit(); - } + } fdClose(cxcharsetmap, 0); /** Now pull out the current charset and free the rest **/ thisCharsetPtr = stLookup(CxGlobals.CharsetMap, nl_langinfo(CODESET)); - if(thisCharsetPtr){ + if(thisCharsetPtr) + { stSeparate(thisCharsetPtr); stFreeInf(CxGlobals.CharsetMap); CxGlobals.CharsetMap = thisCharsetPtr; - - } - else{ + } + else + { printf("centrallix: could not find current charset '%s' in '%s'\n", nl_langinfo(CODESET), charsetmapFileName); thExit(); - } + } /** This setting can be dangerous apart from the RBAC security subsystem. From c224a0cd3bcf45a4012751f91ac29bc748e2fd79 Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Fri, 7 Oct 2011 23:09:21 -0600 Subject: [PATCH 019/124] Fix hints default expression decoding in javascript. --- centrallix-os/sys/js/ht_utils_hints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/centrallix-os/sys/js/ht_utils_hints.js b/centrallix-os/sys/js/ht_utils_hints.js index 28e65464a..05d7598fa 100644 --- a/centrallix-os/sys/js/ht_utils_hints.js +++ b/centrallix-os/sys/js/ht_utils_hints.js @@ -244,7 +244,7 @@ function cx_parse_hints(hstr) switch(attrval[0]) { case "d": - ph.efaultExpr = decodeURIComponent(attrval[1]); + ph.DefaultExpr = decodeURIComponent(attrval[1]); break; case "c": ph.Constraint = decodeURIComponent(attrval[1]); From abcf6cc46dae61c402557d6fc26496415e9ebe1d Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Fri, 7 Oct 2011 23:31:23 -0600 Subject: [PATCH 020/124] Allow ascii() SQL function to handle a NULL parameter (singlebyte and UTF8) --- centrallix/expression/exp_functions.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 3858352b2..7341c9372 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -432,7 +432,7 @@ int exp_fn_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpre mssError(1,"EXP","ascii() function takes a string parameter."); return -1; } - if (i0->String[0] == '\0') + if ((i0->Flags & EXPR_F_NULL) || i0->String[0] == '\0') tree->Flags |= EXPR_F_NULL; else tree->Integer = i0->String[0]; @@ -2188,7 +2188,7 @@ int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, p mssError(1, "EXP", "ascii() function takes a string parameter."); return -1; } - if (i0->String[0] == '\0') + if ((i0->Flags & EXPR_F_NULL) || i0->String[0] == '\0') tree->Flags |= EXPR_F_NULL; charValue = chrGetCharNumber(i0->String); @@ -2278,7 +2278,7 @@ int exp_fn_utf8_lower(pExpression tree, pParamObjects objlist, pExpression i0, p tree->DataType = DATA_T_STRING; if (!i0 || i0->DataType != DATA_T_STRING) { - mssError(1, "EXP", "One string parameter required for upper()"); + mssError(1, "EXP", "One string parameter required for lower()"); return -1; } if (i0->Flags & EXPR_F_NULL) @@ -2510,8 +2510,8 @@ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, } int -exp_internal_DefineFunctions() { - +exp_internal_DefineFunctions() + { /** Function list for EXPR_N_FUNCTION nodes **/ xhAdd(&EXP.Functions, "getdate", (char*) exp_fn_getdate); xhAdd(&EXP.Functions, "user_name", (char*) exp_fn_user_name); From dcd324ee0546bce78b9264d6b06ec001baed3081 Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Mon, 10 Oct 2011 11:39:03 -0600 Subject: [PATCH 021/124] Partial UTF-8 / international charset support for report writer PS/PDF - Added conversion to UTF-16 and glyph table lookup for postscript output (which also includes PDF output). - Glyph table obtained from Adobe, license compatible with GPL. - Glyph table modified for canonicalization and importation into C code - Still need to auto-select the correct font that has the requested glyph(s) in it. For instance - CJK fonts, etc. Right now, output formatter only uses times, helvetica, and courier, which are usually encoded in iso-8859-1. --- centrallix/Makefile.in | 1 + centrallix/report/prtmgmt_v3_od_ps.c | 76 +- centrallix/report/prtmgmt_v3_od_ps_glyphs.c | 4387 +++++++++++++++++++ 3 files changed, 4457 insertions(+), 7 deletions(-) create mode 100644 centrallix/report/prtmgmt_v3_od_ps_glyphs.c diff --git a/centrallix/Makefile.in b/centrallix/Makefile.in index 71cead003..939860fca 100755 --- a/centrallix/Makefile.in +++ b/centrallix/Makefile.in @@ -273,6 +273,7 @@ XV3RPTMODS=prtmgmt_v3_api.o \ prtmgmt_v3_od_pcl.o \ prtmgmt_v3_od_text.o \ prtmgmt_v3_od_ps.o \ + prtmgmt_v3_od_ps_glyphs.o \ prtmgmt_v3_od_epsonfx.o \ prtmgmt_v3_session.o V3RPTMODS=$(patsubst %,report/%,$(XV3RPTMODS)) diff --git a/centrallix/report/prtmgmt_v3_od_ps.c b/centrallix/report/prtmgmt_v3_od_ps.c index 46b4b4533..254fdd494 100644 --- a/centrallix/report/prtmgmt_v3_od_ps.c +++ b/centrallix/report/prtmgmt_v3_od_ps.c @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include "barcode.h" #include "report.h" #include "cxlib/mtask.h" @@ -178,6 +181,7 @@ typedef struct _PPS pSemaphore CompletionSem; int ChildPID; char Buffer[512]; + iconv_t iconv_session; } PrtPsodInf, *pPrtPsodInf; @@ -185,6 +189,8 @@ typedef struct _PPS #define PRT_PSOD_F_SENTPAGE 2 /* sent PageSetup */ #define PRT_PSOD_F_USEGS 4 /* send content through GhostScript */ +extern int psod_internal_LoadGlyphs(); +extern char* psod_glyphs[]; /*** prt_psod_Output() - outputs the given snippet of text or PS code *** to the output channel for the printing session. If length is set @@ -471,6 +477,9 @@ prt_psod_Open(pPrtSession s) context->SelectedStyle.FontID = PRT_FONT_T_MONOSPACE; context->SelectedStyle.Color = 0x00000000; /* black */ + /** Open iconv session for charset conversions **/ + context->iconv_session = iconv_open("UTF-16LE//TRANSLIT", nl_langinfo(CODESET)); + return (void*)context; } @@ -562,6 +571,9 @@ prt_psod_OpenPDF(pPrtSession session) context->TransRPipe = fdOpenFD(rfds[0], O_RDWR); context->CompletionSem = syCreateSem(0, 0); + /** Open iconv session for charset conversions **/ + context->iconv_session = iconv_open("UTF-16LE//TRANSLIT", nl_langinfo(CODESET)); + /** Start the worker thread **/ thCreate(prt_psod_Worker, 0, context); @@ -584,6 +596,8 @@ prt_psod_Close(void* context_v) context->PageNum); /** Free the context structure **/ + if (context->iconv_session != (iconv_t)-1) + iconv_close(context->iconv_session); if (context->TransWPipe) { fdClose(context->TransWPipe, 0); @@ -838,6 +852,12 @@ prt_psod_WriteText(void* context_v, char* str) pPrtPsodInf context = (pPrtPsodInf)context_v; double bl; int i,psbuflen; + char* sptr; + unsigned short outbuf[2]; + int len; + size_t ic, oc; + char* dptr; + char* glyph; prt_psod_BeforeDraw(context); @@ -850,15 +870,54 @@ prt_psod_WriteText(void* context_v, char* str) /** output it. **/ /** wrap content in parentheses and show command **/ context->Buffer[0] = '\0'; - for(i=psbuflen=0;iBuffer+psbuflen, "%2.2X", str[i]); - psbuflen += 2; - if (psbuflen >= sizeof(context->Buffer)-1) + if (!(((unsigned char*)str)[i] & 0x80)) + { + sprintf(context->Buffer+psbuflen, "%2.2X", str[i]); + psbuflen += 2; + if (psbuflen >= sizeof(context->Buffer)-1 || (((unsigned char*)str)[i+1] & 0x80)) + { + prt_psod_Output_va(context, "<%s> show\n", context->Buffer); + psbuflen = 0; + context->Buffer[0] = '\0'; + } + } + else if (context->iconv_session != (iconv_t)-1) { - prt_psod_Output_va(context, "<%s> show\n", context->Buffer); - psbuflen = 0; - context->Buffer[0] = '\0'; + /** Convert *one* character to utf-16 and get its glyph name **/ + sptr = str+i; + ic = len-i; + oc = 2; + outbuf[0] = 0; + dptr = (char*)outbuf; + errno = 0; + iconv(context->iconv_session, &sptr, &ic, &dptr, &oc); + if (errno == EILSEQ || errno == EINVAL || outbuf[0] == 0) + { + /** Failed conversion **/ + prt_psod_Output_va(context, "/.notdef glyphshow\n"); + } + else + { + /** See if this code has a valid glyph for postscript **/ + glyph = psod_glyphs[outbuf[0]]; + if (glyph) + prt_psod_Output_va(context, "/%s glyphshow\n", glyph); + else + prt_psod_Output_va(context, "/.notdef glyphshow\n"); + } + if (ic < len-i) + { + /** Advance the input cnt if we converted a char **/ + i += ((len-i) - ic) - 1; + } + } + else + { + /** Just output the char if we can't convert to UTF-16. **/ + prt_psod_Output_va(context, "<%2.2X> show\n", str[i]); } } if (psbuflen) @@ -995,6 +1054,9 @@ prt_psod_Initialize() pPrtOutputDriver drv; int i; + /** Load the glyph definitions **/ + psod_internal_LoadGlyphs(); + /** Register the PostScript version of the driver **/ drv = prt_strictfm_AllocDriver(); strcpy(drv->Name,"ps"); diff --git a/centrallix/report/prtmgmt_v3_od_ps_glyphs.c b/centrallix/report/prtmgmt_v3_od_ps_glyphs.c new file mode 100644 index 000000000..b2c6514aa --- /dev/null +++ b/centrallix/report/prtmgmt_v3_od_ps_glyphs.c @@ -0,0 +1,4387 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "barcode.h" +#include "report.h" +#include "cxlib/mtask.h" +#include "cxlib/magic.h" +#include "cxlib/xarray.h" +#include "cxlib/xstring.h" +#include "prtmgmt_v3/prtmgmt_v3.h" +#include "htmlparse.h" +#include "cxlib/mtsession.h" +#include "config.h" +#include "assert.h" + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2011 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: prtmgmt_v3_od_ps_glyphs.c */ +/* Author: Greg Beeley */ +/* Date: 07-Oct-2011 */ +/* */ +/* Description: UTF16-to-Glyph correlation table for Postscript. */ +/************************************************************************/ + +/*** This file was derived from Adobe's Glyph List. It is not a copy or + *** a version of that Glyph List and if you need the official list, go to + *** Adobe's website (see below) and fetch it. :) + *** + *** License that came with the Adobe glyph list: +# ########################################################################### +# Copyright (c) 1997,1998,2002,2007 Adobe Systems Incorporated +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this documentation file to use, copy, publish, distribute, +# sublicense, and/or sell copies of the documentation, and to permit +# others to do the same, provided that: +# - No modification, editing or other alteration of this document is +# allowed; and +# - The above copyright notice and this permission notice shall be +# included in all copies of the documentation. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this documentation file, to create their own derivative works +# from the content of this document to use, copy, publish, distribute, +# sublicense, and/or sell the derivative works, and to permit others to do +# the same, provided that the derived work is not represented as being a +# copy or version of this document. +# +# Adobe shall not be liable to any party for any loss of revenue or profit +# or for indirect, incidental, special, consequential, or other similar +# damages, whether based on tort (including without limitation negligence +# or strict liability), contract or other legal or equitable grounds even +# if Adobe has been advised or had reason to know of the possibility of +# such damages. The Adobe materials are provided on an "AS IS" basis. +# Adobe specifically disclaims all express, statutory, or implied +# warranties relating to the Adobe materials, including but not limited to +# those concerning merchantability or fitness for a particular purpose or +# non-infringement of any third party rights regarding the Adobe +# materials. +# ########################################################################### +# Name: Adobe Glyph List +# Table version: 2.0 +# Date: September 20, 2002 +# +# See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html +***/ + + +char* psod_glyphs[65536]; + +int +psod_internal_LoadGlyphs() + { + + memset(psod_glyphs, 0, sizeof(psod_glyphs)); + + psod_glyphs[0x0041] = "A"; + psod_glyphs[0x00C6] = "AE"; + psod_glyphs[0x01FC] = "AEacute"; + psod_glyphs[0x01E2] = "AEmacron"; + psod_glyphs[0xF7E6] = "AEsmall"; + psod_glyphs[0x00C1] = "Aacute"; + psod_glyphs[0xF7E1] = "Aacutesmall"; + psod_glyphs[0x0102] = "Abreve"; + psod_glyphs[0x1EAE] = "Abreveacute"; + psod_glyphs[0x04D0] = "Abrevecyrillic"; + psod_glyphs[0x1EB6] = "Abrevedotbelow"; + psod_glyphs[0x1EB0] = "Abrevegrave"; + psod_glyphs[0x1EB2] = "Abrevehookabove"; + psod_glyphs[0x1EB4] = "Abrevetilde"; + psod_glyphs[0x01CD] = "Acaron"; + psod_glyphs[0x24B6] = "Acircle"; + psod_glyphs[0x00C2] = "Acircumflex"; + psod_glyphs[0x1EA4] = "Acircumflexacute"; + psod_glyphs[0x1EAC] = "Acircumflexdotbelow"; + psod_glyphs[0x1EA6] = "Acircumflexgrave"; + psod_glyphs[0x1EA8] = "Acircumflexhookabove"; + psod_glyphs[0xF7E2] = "Acircumflexsmall"; + psod_glyphs[0x1EAA] = "Acircumflextilde"; + psod_glyphs[0xF6C9] = "Acute"; + psod_glyphs[0xF7B4] = "Acutesmall"; + psod_glyphs[0x0410] = "Acyrillic"; + psod_glyphs[0x0200] = "Adblgrave"; + psod_glyphs[0x00C4] = "Adieresis"; + psod_glyphs[0x04D2] = "Adieresiscyrillic"; + psod_glyphs[0x01DE] = "Adieresismacron"; + psod_glyphs[0xF7E4] = "Adieresissmall"; + psod_glyphs[0x1EA0] = "Adotbelow"; + psod_glyphs[0x01E0] = "Adotmacron"; + psod_glyphs[0x00C0] = "Agrave"; + psod_glyphs[0xF7E0] = "Agravesmall"; + psod_glyphs[0x1EA2] = "Ahookabove"; + psod_glyphs[0x04D4] = "Aiecyrillic"; + psod_glyphs[0x0202] = "Ainvertedbreve"; + psod_glyphs[0x0391] = "Alpha"; + psod_glyphs[0x0386] = "Alphatonos"; + psod_glyphs[0x0100] = "Amacron"; + psod_glyphs[0xFF21] = "Amonospace"; + psod_glyphs[0x0104] = "Aogonek"; + psod_glyphs[0x00C5] = "Aring"; + psod_glyphs[0x01FA] = "Aringacute"; + psod_glyphs[0x1E00] = "Aringbelow"; + psod_glyphs[0xF7E5] = "Aringsmall"; + psod_glyphs[0xF761] = "Asmall"; + psod_glyphs[0x00C3] = "Atilde"; + psod_glyphs[0xF7E3] = "Atildesmall"; + psod_glyphs[0x0531] = "Aybarmenian"; + psod_glyphs[0x0042] = "B"; + psod_glyphs[0x24B7] = "Bcircle"; + psod_glyphs[0x1E02] = "Bdotaccent"; + psod_glyphs[0x1E04] = "Bdotbelow"; + psod_glyphs[0x0411] = "Becyrillic"; + psod_glyphs[0x0532] = "Benarmenian"; + psod_glyphs[0x0392] = "Beta"; + psod_glyphs[0x0181] = "Bhook"; + psod_glyphs[0x1E06] = "Blinebelow"; + psod_glyphs[0xFF22] = "Bmonospace"; + psod_glyphs[0xF6F4] = "Brevesmall"; + psod_glyphs[0xF762] = "Bsmall"; + psod_glyphs[0x0182] = "Btopbar"; + psod_glyphs[0x0043] = "C"; + psod_glyphs[0x053E] = "Caarmenian"; + psod_glyphs[0x0106] = "Cacute"; + psod_glyphs[0xF6CA] = "Caron"; + psod_glyphs[0xF6F5] = "Caronsmall"; + psod_glyphs[0x010C] = "Ccaron"; + psod_glyphs[0x00C7] = "Ccedilla"; + psod_glyphs[0x1E08] = "Ccedillaacute"; + psod_glyphs[0xF7E7] = "Ccedillasmall"; + psod_glyphs[0x24B8] = "Ccircle"; + psod_glyphs[0x0108] = "Ccircumflex"; + psod_glyphs[0x010A] = "Cdot"; + psod_glyphs[0x010A] = "Cdotaccent"; + psod_glyphs[0xF7B8] = "Cedillasmall"; + psod_glyphs[0x0549] = "Chaarmenian"; + psod_glyphs[0x04BC] = "Cheabkhasiancyrillic"; + psod_glyphs[0x0427] = "Checyrillic"; + psod_glyphs[0x04BE] = "Chedescenderabkhasiancyrillic"; + psod_glyphs[0x04B6] = "Chedescendercyrillic"; + psod_glyphs[0x04F4] = "Chedieresiscyrillic"; + psod_glyphs[0x0543] = "Cheharmenian"; + psod_glyphs[0x04CB] = "Chekhakassiancyrillic"; + psod_glyphs[0x04B8] = "Cheverticalstrokecyrillic"; + psod_glyphs[0x03A7] = "Chi"; + psod_glyphs[0x0187] = "Chook"; + psod_glyphs[0xF6F6] = "Circumflexsmall"; + psod_glyphs[0xFF23] = "Cmonospace"; + psod_glyphs[0x0551] = "Coarmenian"; + psod_glyphs[0xF763] = "Csmall"; + psod_glyphs[0x0044] = "D"; + psod_glyphs[0x01F1] = "DZ"; + psod_glyphs[0x01C4] = "DZcaron"; + psod_glyphs[0x0534] = "Daarmenian"; + psod_glyphs[0x0189] = "Dafrican"; + psod_glyphs[0x010E] = "Dcaron"; + psod_glyphs[0x1E10] = "Dcedilla"; + psod_glyphs[0x24B9] = "Dcircle"; + psod_glyphs[0x1E12] = "Dcircumflexbelow"; + psod_glyphs[0x0110] = "Dcroat"; + psod_glyphs[0x1E0A] = "Ddotaccent"; + psod_glyphs[0x1E0C] = "Ddotbelow"; + psod_glyphs[0x0414] = "Decyrillic"; + psod_glyphs[0x03EE] = "Deicoptic"; + psod_glyphs[0x2206] = "Delta"; + psod_glyphs[0x0394] = "Deltagreek"; + psod_glyphs[0x018A] = "Dhook"; + psod_glyphs[0xF6CB] = "Dieresis"; + psod_glyphs[0xF6CC] = "DieresisAcute"; + psod_glyphs[0xF6CD] = "DieresisGrave"; + psod_glyphs[0xF7A8] = "Dieresissmall"; + psod_glyphs[0x03DC] = "Digammagreek"; + psod_glyphs[0x0402] = "Djecyrillic"; + psod_glyphs[0x1E0E] = "Dlinebelow"; + psod_glyphs[0xFF24] = "Dmonospace"; + psod_glyphs[0xF6F7] = "Dotaccentsmall"; + psod_glyphs[0x0110] = "Dslash"; + psod_glyphs[0xF764] = "Dsmall"; + psod_glyphs[0x018B] = "Dtopbar"; + psod_glyphs[0x01F2] = "Dz"; + psod_glyphs[0x01C5] = "Dzcaron"; + psod_glyphs[0x04E0] = "Dzeabkhasiancyrillic"; + psod_glyphs[0x0405] = "Dzecyrillic"; + psod_glyphs[0x040F] = "Dzhecyrillic"; + psod_glyphs[0x0045] = "E"; + psod_glyphs[0x00C9] = "Eacute"; + psod_glyphs[0xF7E9] = "Eacutesmall"; + psod_glyphs[0x0114] = "Ebreve"; + psod_glyphs[0x011A] = "Ecaron"; + psod_glyphs[0x1E1C] = "Ecedillabreve"; + psod_glyphs[0x0535] = "Echarmenian"; + psod_glyphs[0x24BA] = "Ecircle"; + psod_glyphs[0x00CA] = "Ecircumflex"; + psod_glyphs[0x1EBE] = "Ecircumflexacute"; + psod_glyphs[0x1E18] = "Ecircumflexbelow"; + psod_glyphs[0x1EC6] = "Ecircumflexdotbelow"; + psod_glyphs[0x1EC0] = "Ecircumflexgrave"; + psod_glyphs[0x1EC2] = "Ecircumflexhookabove"; + psod_glyphs[0xF7EA] = "Ecircumflexsmall"; + psod_glyphs[0x1EC4] = "Ecircumflextilde"; + psod_glyphs[0x0404] = "Ecyrillic"; + psod_glyphs[0x0204] = "Edblgrave"; + psod_glyphs[0x00CB] = "Edieresis"; + psod_glyphs[0xF7EB] = "Edieresissmall"; + psod_glyphs[0x0116] = "Edot"; + psod_glyphs[0x0116] = "Edotaccent"; + psod_glyphs[0x1EB8] = "Edotbelow"; + psod_glyphs[0x0424] = "Efcyrillic"; + psod_glyphs[0x00C8] = "Egrave"; + psod_glyphs[0xF7E8] = "Egravesmall"; + psod_glyphs[0x0537] = "Eharmenian"; + psod_glyphs[0x1EBA] = "Ehookabove"; + psod_glyphs[0x2167] = "Eightroman"; + psod_glyphs[0x0206] = "Einvertedbreve"; + psod_glyphs[0x0464] = "Eiotifiedcyrillic"; + psod_glyphs[0x041B] = "Elcyrillic"; + psod_glyphs[0x216A] = "Elevenroman"; + psod_glyphs[0x0112] = "Emacron"; + psod_glyphs[0x1E16] = "Emacronacute"; + psod_glyphs[0x1E14] = "Emacrongrave"; + psod_glyphs[0x041C] = "Emcyrillic"; + psod_glyphs[0xFF25] = "Emonospace"; + psod_glyphs[0x041D] = "Encyrillic"; + psod_glyphs[0x04A2] = "Endescendercyrillic"; + psod_glyphs[0x014A] = "Eng"; + psod_glyphs[0x04A4] = "Enghecyrillic"; + psod_glyphs[0x04C7] = "Enhookcyrillic"; + psod_glyphs[0x0118] = "Eogonek"; + psod_glyphs[0x0190] = "Eopen"; + psod_glyphs[0x0395] = "Epsilon"; + psod_glyphs[0x0388] = "Epsilontonos"; + psod_glyphs[0x0420] = "Ercyrillic"; + psod_glyphs[0x018E] = "Ereversed"; + psod_glyphs[0x042D] = "Ereversedcyrillic"; + psod_glyphs[0x0421] = "Escyrillic"; + psod_glyphs[0x04AA] = "Esdescendercyrillic"; + psod_glyphs[0x01A9] = "Esh"; + psod_glyphs[0xF765] = "Esmall"; + psod_glyphs[0x0397] = "Eta"; + psod_glyphs[0x0538] = "Etarmenian"; + psod_glyphs[0x0389] = "Etatonos"; + psod_glyphs[0x00D0] = "Eth"; + psod_glyphs[0xF7F0] = "Ethsmall"; + psod_glyphs[0x1EBC] = "Etilde"; + psod_glyphs[0x1E1A] = "Etildebelow"; + psod_glyphs[0x20AC] = "Euro"; + psod_glyphs[0x01B7] = "Ezh"; + psod_glyphs[0x01EE] = "Ezhcaron"; + psod_glyphs[0x01B8] = "Ezhreversed"; + psod_glyphs[0x0046] = "F"; + psod_glyphs[0x24BB] = "Fcircle"; + psod_glyphs[0x1E1E] = "Fdotaccent"; + psod_glyphs[0x0556] = "Feharmenian"; + psod_glyphs[0x03E4] = "Feicoptic"; + psod_glyphs[0x0191] = "Fhook"; + psod_glyphs[0x0472] = "Fitacyrillic"; + psod_glyphs[0x2164] = "Fiveroman"; + psod_glyphs[0xFF26] = "Fmonospace"; + psod_glyphs[0x2163] = "Fourroman"; + psod_glyphs[0xF766] = "Fsmall"; + psod_glyphs[0x0047] = "G"; + psod_glyphs[0x3387] = "GBsquare"; + psod_glyphs[0x01F4] = "Gacute"; + psod_glyphs[0x0393] = "Gamma"; + psod_glyphs[0x0194] = "Gammaafrican"; + psod_glyphs[0x03EA] = "Gangiacoptic"; + psod_glyphs[0x011E] = "Gbreve"; + psod_glyphs[0x01E6] = "Gcaron"; + psod_glyphs[0x0122] = "Gcedilla"; + psod_glyphs[0x24BC] = "Gcircle"; + psod_glyphs[0x011C] = "Gcircumflex"; + psod_glyphs[0x0122] = "Gcommaaccent"; + psod_glyphs[0x0120] = "Gdot"; + psod_glyphs[0x0120] = "Gdotaccent"; + psod_glyphs[0x0413] = "Gecyrillic"; + psod_glyphs[0x0542] = "Ghadarmenian"; + psod_glyphs[0x0494] = "Ghemiddlehookcyrillic"; + psod_glyphs[0x0492] = "Ghestrokecyrillic"; + psod_glyphs[0x0490] = "Gheupturncyrillic"; + psod_glyphs[0x0193] = "Ghook"; + psod_glyphs[0x0533] = "Gimarmenian"; + psod_glyphs[0x0403] = "Gjecyrillic"; + psod_glyphs[0x1E20] = "Gmacron"; + psod_glyphs[0xFF27] = "Gmonospace"; + psod_glyphs[0xF6CE] = "Grave"; + psod_glyphs[0xF760] = "Gravesmall"; + psod_glyphs[0xF767] = "Gsmall"; + psod_glyphs[0x029B] = "Gsmallhook"; + psod_glyphs[0x01E4] = "Gstroke"; + psod_glyphs[0x0048] = "H"; + psod_glyphs[0x25CF] = "H18533"; + psod_glyphs[0x25AA] = "H18543"; + psod_glyphs[0x25AB] = "H18551"; + psod_glyphs[0x25A1] = "H22073"; + psod_glyphs[0x33CB] = "HPsquare"; + psod_glyphs[0x04A8] = "Haabkhasiancyrillic"; + psod_glyphs[0x04B2] = "Hadescendercyrillic"; + psod_glyphs[0x042A] = "Hardsigncyrillic"; + psod_glyphs[0x0126] = "Hbar"; + psod_glyphs[0x1E2A] = "Hbrevebelow"; + psod_glyphs[0x1E28] = "Hcedilla"; + psod_glyphs[0x24BD] = "Hcircle"; + psod_glyphs[0x0124] = "Hcircumflex"; + psod_glyphs[0x1E26] = "Hdieresis"; + psod_glyphs[0x1E22] = "Hdotaccent"; + psod_glyphs[0x1E24] = "Hdotbelow"; + psod_glyphs[0xFF28] = "Hmonospace"; + psod_glyphs[0x0540] = "Hoarmenian"; + psod_glyphs[0x03E8] = "Horicoptic"; + psod_glyphs[0xF768] = "Hsmall"; + psod_glyphs[0xF6CF] = "Hungarumlaut"; + psod_glyphs[0xF6F8] = "Hungarumlautsmall"; + psod_glyphs[0x3390] = "Hzsquare"; + psod_glyphs[0x0049] = "I"; + psod_glyphs[0x042F] = "IAcyrillic"; + psod_glyphs[0x0132] = "IJ"; + psod_glyphs[0x042E] = "IUcyrillic"; + psod_glyphs[0x00CD] = "Iacute"; + psod_glyphs[0xF7ED] = "Iacutesmall"; + psod_glyphs[0x012C] = "Ibreve"; + psod_glyphs[0x01CF] = "Icaron"; + psod_glyphs[0x24BE] = "Icircle"; + psod_glyphs[0x00CE] = "Icircumflex"; + psod_glyphs[0xF7EE] = "Icircumflexsmall"; + psod_glyphs[0x0406] = "Icyrillic"; + psod_glyphs[0x0208] = "Idblgrave"; + psod_glyphs[0x00CF] = "Idieresis"; + psod_glyphs[0x1E2E] = "Idieresisacute"; + psod_glyphs[0x04E4] = "Idieresiscyrillic"; + psod_glyphs[0xF7EF] = "Idieresissmall"; + psod_glyphs[0x0130] = "Idot"; + psod_glyphs[0x0130] = "Idotaccent"; + psod_glyphs[0x1ECA] = "Idotbelow"; + psod_glyphs[0x04D6] = "Iebrevecyrillic"; + psod_glyphs[0x0415] = "Iecyrillic"; + psod_glyphs[0x2111] = "Ifraktur"; + psod_glyphs[0x00CC] = "Igrave"; + psod_glyphs[0xF7EC] = "Igravesmall"; + psod_glyphs[0x1EC8] = "Ihookabove"; + psod_glyphs[0x0418] = "Iicyrillic"; + psod_glyphs[0x020A] = "Iinvertedbreve"; + psod_glyphs[0x0419] = "Iishortcyrillic"; + psod_glyphs[0x012A] = "Imacron"; + psod_glyphs[0x04E2] = "Imacroncyrillic"; + psod_glyphs[0xFF29] = "Imonospace"; + psod_glyphs[0x053B] = "Iniarmenian"; + psod_glyphs[0x0401] = "Iocyrillic"; + psod_glyphs[0x012E] = "Iogonek"; + psod_glyphs[0x0399] = "Iota"; + psod_glyphs[0x0196] = "Iotaafrican"; + psod_glyphs[0x03AA] = "Iotadieresis"; + psod_glyphs[0x038A] = "Iotatonos"; + psod_glyphs[0xF769] = "Ismall"; + psod_glyphs[0x0197] = "Istroke"; + psod_glyphs[0x0128] = "Itilde"; + psod_glyphs[0x1E2C] = "Itildebelow"; + psod_glyphs[0x0474] = "Izhitsacyrillic"; + psod_glyphs[0x0476] = "Izhitsadblgravecyrillic"; + psod_glyphs[0x004A] = "J"; + psod_glyphs[0x0541] = "Jaarmenian"; + psod_glyphs[0x24BF] = "Jcircle"; + psod_glyphs[0x0134] = "Jcircumflex"; + psod_glyphs[0x0408] = "Jecyrillic"; + psod_glyphs[0x054B] = "Jheharmenian"; + psod_glyphs[0xFF2A] = "Jmonospace"; + psod_glyphs[0xF76A] = "Jsmall"; + psod_glyphs[0x004B] = "K"; + psod_glyphs[0x3385] = "KBsquare"; + psod_glyphs[0x33CD] = "KKsquare"; + psod_glyphs[0x04A0] = "Kabashkircyrillic"; + psod_glyphs[0x1E30] = "Kacute"; + psod_glyphs[0x041A] = "Kacyrillic"; + psod_glyphs[0x049A] = "Kadescendercyrillic"; + psod_glyphs[0x04C3] = "Kahookcyrillic"; + psod_glyphs[0x039A] = "Kappa"; + psod_glyphs[0x049E] = "Kastrokecyrillic"; + psod_glyphs[0x049C] = "Kaverticalstrokecyrillic"; + psod_glyphs[0x01E8] = "Kcaron"; + psod_glyphs[0x0136] = "Kcedilla"; + psod_glyphs[0x24C0] = "Kcircle"; + psod_glyphs[0x0136] = "Kcommaaccent"; + psod_glyphs[0x1E32] = "Kdotbelow"; + psod_glyphs[0x0554] = "Keharmenian"; + psod_glyphs[0x053F] = "Kenarmenian"; + psod_glyphs[0x0425] = "Khacyrillic"; + psod_glyphs[0x03E6] = "Kheicoptic"; + psod_glyphs[0x0198] = "Khook"; + psod_glyphs[0x040C] = "Kjecyrillic"; + psod_glyphs[0x1E34] = "Klinebelow"; + psod_glyphs[0xFF2B] = "Kmonospace"; + psod_glyphs[0x0480] = "Koppacyrillic"; + psod_glyphs[0x03DE] = "Koppagreek"; + psod_glyphs[0x046E] = "Ksicyrillic"; + psod_glyphs[0xF76B] = "Ksmall"; + psod_glyphs[0x004C] = "L"; + psod_glyphs[0x01C7] = "LJ"; + psod_glyphs[0xF6BF] = "LL"; + psod_glyphs[0x0139] = "Lacute"; + psod_glyphs[0x039B] = "Lambda"; + psod_glyphs[0x013D] = "Lcaron"; + psod_glyphs[0x013B] = "Lcedilla"; + psod_glyphs[0x24C1] = "Lcircle"; + psod_glyphs[0x1E3C] = "Lcircumflexbelow"; + psod_glyphs[0x013B] = "Lcommaaccent"; + psod_glyphs[0x013F] = "Ldot"; + psod_glyphs[0x013F] = "Ldotaccent"; + psod_glyphs[0x1E36] = "Ldotbelow"; + psod_glyphs[0x1E38] = "Ldotbelowmacron"; + psod_glyphs[0x053C] = "Liwnarmenian"; + psod_glyphs[0x01C8] = "Lj"; + psod_glyphs[0x0409] = "Ljecyrillic"; + psod_glyphs[0x1E3A] = "Llinebelow"; + psod_glyphs[0xFF2C] = "Lmonospace"; + psod_glyphs[0x0141] = "Lslash"; + psod_glyphs[0xF6F9] = "Lslashsmall"; + psod_glyphs[0xF76C] = "Lsmall"; + psod_glyphs[0x004D] = "M"; + psod_glyphs[0x3386] = "MBsquare"; + psod_glyphs[0xF6D0] = "Macron"; + psod_glyphs[0xF7AF] = "Macronsmall"; + psod_glyphs[0x1E3E] = "Macute"; + psod_glyphs[0x24C2] = "Mcircle"; + psod_glyphs[0x1E40] = "Mdotaccent"; + psod_glyphs[0x1E42] = "Mdotbelow"; + psod_glyphs[0x0544] = "Menarmenian"; + psod_glyphs[0xFF2D] = "Mmonospace"; + psod_glyphs[0xF76D] = "Msmall"; + psod_glyphs[0x019C] = "Mturned"; + psod_glyphs[0x039C] = "Mu"; + psod_glyphs[0x004E] = "N"; + psod_glyphs[0x01CA] = "NJ"; + psod_glyphs[0x0143] = "Nacute"; + psod_glyphs[0x0147] = "Ncaron"; + psod_glyphs[0x0145] = "Ncedilla"; + psod_glyphs[0x24C3] = "Ncircle"; + psod_glyphs[0x1E4A] = "Ncircumflexbelow"; + psod_glyphs[0x0145] = "Ncommaaccent"; + psod_glyphs[0x1E44] = "Ndotaccent"; + psod_glyphs[0x1E46] = "Ndotbelow"; + psod_glyphs[0x019D] = "Nhookleft"; + psod_glyphs[0x2168] = "Nineroman"; + psod_glyphs[0x01CB] = "Nj"; + psod_glyphs[0x040A] = "Njecyrillic"; + psod_glyphs[0x1E48] = "Nlinebelow"; + psod_glyphs[0xFF2E] = "Nmonospace"; + psod_glyphs[0x0546] = "Nowarmenian"; + psod_glyphs[0xF76E] = "Nsmall"; + psod_glyphs[0x00D1] = "Ntilde"; + psod_glyphs[0xF7F1] = "Ntildesmall"; + psod_glyphs[0x039D] = "Nu"; + psod_glyphs[0x004F] = "O"; + psod_glyphs[0x0152] = "OE"; + psod_glyphs[0xF6FA] = "OEsmall"; + psod_glyphs[0x00D3] = "Oacute"; + psod_glyphs[0xF7F3] = "Oacutesmall"; + psod_glyphs[0x04E8] = "Obarredcyrillic"; + psod_glyphs[0x04EA] = "Obarreddieresiscyrillic"; + psod_glyphs[0x014E] = "Obreve"; + psod_glyphs[0x01D1] = "Ocaron"; + psod_glyphs[0x019F] = "Ocenteredtilde"; + psod_glyphs[0x24C4] = "Ocircle"; + psod_glyphs[0x00D4] = "Ocircumflex"; + psod_glyphs[0x1ED0] = "Ocircumflexacute"; + psod_glyphs[0x1ED8] = "Ocircumflexdotbelow"; + psod_glyphs[0x1ED2] = "Ocircumflexgrave"; + psod_glyphs[0x1ED4] = "Ocircumflexhookabove"; + psod_glyphs[0xF7F4] = "Ocircumflexsmall"; + psod_glyphs[0x1ED6] = "Ocircumflextilde"; + psod_glyphs[0x041E] = "Ocyrillic"; + psod_glyphs[0x0150] = "Odblacute"; + psod_glyphs[0x020C] = "Odblgrave"; + psod_glyphs[0x00D6] = "Odieresis"; + psod_glyphs[0x04E6] = "Odieresiscyrillic"; + psod_glyphs[0xF7F6] = "Odieresissmall"; + psod_glyphs[0x1ECC] = "Odotbelow"; + psod_glyphs[0xF6FB] = "Ogoneksmall"; + psod_glyphs[0x00D2] = "Ograve"; + psod_glyphs[0xF7F2] = "Ogravesmall"; + psod_glyphs[0x0555] = "Oharmenian"; + psod_glyphs[0x2126] = "Ohm"; + psod_glyphs[0x1ECE] = "Ohookabove"; + psod_glyphs[0x01A0] = "Ohorn"; + psod_glyphs[0x1EDA] = "Ohornacute"; + psod_glyphs[0x1EE2] = "Ohorndotbelow"; + psod_glyphs[0x1EDC] = "Ohorngrave"; + psod_glyphs[0x1EDE] = "Ohornhookabove"; + psod_glyphs[0x1EE0] = "Ohorntilde"; + psod_glyphs[0x0150] = "Ohungarumlaut"; + psod_glyphs[0x01A2] = "Oi"; + psod_glyphs[0x020E] = "Oinvertedbreve"; + psod_glyphs[0x014C] = "Omacron"; + psod_glyphs[0x1E52] = "Omacronacute"; + psod_glyphs[0x1E50] = "Omacrongrave"; + psod_glyphs[0x2126] = "Omega"; + psod_glyphs[0x0460] = "Omegacyrillic"; + psod_glyphs[0x03A9] = "Omegagreek"; + psod_glyphs[0x047A] = "Omegaroundcyrillic"; + psod_glyphs[0x047C] = "Omegatitlocyrillic"; + psod_glyphs[0x038F] = "Omegatonos"; + psod_glyphs[0x039F] = "Omicron"; + psod_glyphs[0x038C] = "Omicrontonos"; + psod_glyphs[0xFF2F] = "Omonospace"; + psod_glyphs[0x2160] = "Oneroman"; + psod_glyphs[0x01EA] = "Oogonek"; + psod_glyphs[0x01EC] = "Oogonekmacron"; + psod_glyphs[0x0186] = "Oopen"; + psod_glyphs[0x00D8] = "Oslash"; + psod_glyphs[0x01FE] = "Oslashacute"; + psod_glyphs[0xF7F8] = "Oslashsmall"; + psod_glyphs[0xF76F] = "Osmall"; + psod_glyphs[0x01FE] = "Ostrokeacute"; + psod_glyphs[0x047E] = "Otcyrillic"; + psod_glyphs[0x00D5] = "Otilde"; + psod_glyphs[0x1E4C] = "Otildeacute"; + psod_glyphs[0x1E4E] = "Otildedieresis"; + psod_glyphs[0xF7F5] = "Otildesmall"; + psod_glyphs[0x0050] = "P"; + psod_glyphs[0x1E54] = "Pacute"; + psod_glyphs[0x24C5] = "Pcircle"; + psod_glyphs[0x1E56] = "Pdotaccent"; + psod_glyphs[0x041F] = "Pecyrillic"; + psod_glyphs[0x054A] = "Peharmenian"; + psod_glyphs[0x04A6] = "Pemiddlehookcyrillic"; + psod_glyphs[0x03A6] = "Phi"; + psod_glyphs[0x01A4] = "Phook"; + psod_glyphs[0x03A0] = "Pi"; + psod_glyphs[0x0553] = "Piwrarmenian"; + psod_glyphs[0xFF30] = "Pmonospace"; + psod_glyphs[0x03A8] = "Psi"; + psod_glyphs[0x0470] = "Psicyrillic"; + psod_glyphs[0xF770] = "Psmall"; + psod_glyphs[0x0051] = "Q"; + psod_glyphs[0x24C6] = "Qcircle"; + psod_glyphs[0xFF31] = "Qmonospace"; + psod_glyphs[0xF771] = "Qsmall"; + psod_glyphs[0x0052] = "R"; + psod_glyphs[0x054C] = "Raarmenian"; + psod_glyphs[0x0154] = "Racute"; + psod_glyphs[0x0158] = "Rcaron"; + psod_glyphs[0x0156] = "Rcedilla"; + psod_glyphs[0x24C7] = "Rcircle"; + psod_glyphs[0x0156] = "Rcommaaccent"; + psod_glyphs[0x0210] = "Rdblgrave"; + psod_glyphs[0x1E58] = "Rdotaccent"; + psod_glyphs[0x1E5A] = "Rdotbelow"; + psod_glyphs[0x1E5C] = "Rdotbelowmacron"; + psod_glyphs[0x0550] = "Reharmenian"; + psod_glyphs[0x211C] = "Rfraktur"; + psod_glyphs[0x03A1] = "Rho"; + psod_glyphs[0xF6FC] = "Ringsmall"; + psod_glyphs[0x0212] = "Rinvertedbreve"; + psod_glyphs[0x1E5E] = "Rlinebelow"; + psod_glyphs[0xFF32] = "Rmonospace"; + psod_glyphs[0xF772] = "Rsmall"; + psod_glyphs[0x0281] = "Rsmallinverted"; + psod_glyphs[0x02B6] = "Rsmallinvertedsuperior"; + psod_glyphs[0x0053] = "S"; + psod_glyphs[0x250C] = "SF010000"; + psod_glyphs[0x2514] = "SF020000"; + psod_glyphs[0x2510] = "SF030000"; + psod_glyphs[0x2518] = "SF040000"; + psod_glyphs[0x253C] = "SF050000"; + psod_glyphs[0x252C] = "SF060000"; + psod_glyphs[0x2534] = "SF070000"; + psod_glyphs[0x251C] = "SF080000"; + psod_glyphs[0x2524] = "SF090000"; + psod_glyphs[0x2500] = "SF100000"; + psod_glyphs[0x2502] = "SF110000"; + psod_glyphs[0x2561] = "SF190000"; + psod_glyphs[0x2562] = "SF200000"; + psod_glyphs[0x2556] = "SF210000"; + psod_glyphs[0x2555] = "SF220000"; + psod_glyphs[0x2563] = "SF230000"; + psod_glyphs[0x2551] = "SF240000"; + psod_glyphs[0x2557] = "SF250000"; + psod_glyphs[0x255D] = "SF260000"; + psod_glyphs[0x255C] = "SF270000"; + psod_glyphs[0x255B] = "SF280000"; + psod_glyphs[0x255E] = "SF360000"; + psod_glyphs[0x255F] = "SF370000"; + psod_glyphs[0x255A] = "SF380000"; + psod_glyphs[0x2554] = "SF390000"; + psod_glyphs[0x2569] = "SF400000"; + psod_glyphs[0x2566] = "SF410000"; + psod_glyphs[0x2560] = "SF420000"; + psod_glyphs[0x2550] = "SF430000"; + psod_glyphs[0x256C] = "SF440000"; + psod_glyphs[0x2567] = "SF450000"; + psod_glyphs[0x2568] = "SF460000"; + psod_glyphs[0x2564] = "SF470000"; + psod_glyphs[0x2565] = "SF480000"; + psod_glyphs[0x2559] = "SF490000"; + psod_glyphs[0x2558] = "SF500000"; + psod_glyphs[0x2552] = "SF510000"; + psod_glyphs[0x2553] = "SF520000"; + psod_glyphs[0x256B] = "SF530000"; + psod_glyphs[0x256A] = "SF540000"; + psod_glyphs[0x015A] = "Sacute"; + psod_glyphs[0x1E64] = "Sacutedotaccent"; + psod_glyphs[0x03E0] = "Sampigreek"; + psod_glyphs[0x0160] = "Scaron"; + psod_glyphs[0x1E66] = "Scarondotaccent"; + psod_glyphs[0xF6FD] = "Scaronsmall"; + psod_glyphs[0x015E] = "Scedilla"; + psod_glyphs[0x018F] = "Schwa"; + psod_glyphs[0x04D8] = "Schwacyrillic"; + psod_glyphs[0x04DA] = "Schwadieresiscyrillic"; + psod_glyphs[0x24C8] = "Scircle"; + psod_glyphs[0x015C] = "Scircumflex"; + psod_glyphs[0x0218] = "Scommaaccent"; + psod_glyphs[0x1E60] = "Sdotaccent"; + psod_glyphs[0x1E62] = "Sdotbelow"; + psod_glyphs[0x1E68] = "Sdotbelowdotaccent"; + psod_glyphs[0x054D] = "Seharmenian"; + psod_glyphs[0x2166] = "Sevenroman"; + psod_glyphs[0x0547] = "Shaarmenian"; + psod_glyphs[0x0428] = "Shacyrillic"; + psod_glyphs[0x0429] = "Shchacyrillic"; + psod_glyphs[0x03E2] = "Sheicoptic"; + psod_glyphs[0x04BA] = "Shhacyrillic"; + psod_glyphs[0x03EC] = "Shimacoptic"; + psod_glyphs[0x03A3] = "Sigma"; + psod_glyphs[0x2165] = "Sixroman"; + psod_glyphs[0xFF33] = "Smonospace"; + psod_glyphs[0x042C] = "Softsigncyrillic"; + psod_glyphs[0xF773] = "Ssmall"; + psod_glyphs[0x03DA] = "Stigmagreek"; + psod_glyphs[0x0054] = "T"; + psod_glyphs[0x03A4] = "Tau"; + psod_glyphs[0x0166] = "Tbar"; + psod_glyphs[0x0164] = "Tcaron"; + psod_glyphs[0x0162] = "Tcedilla"; + psod_glyphs[0x24C9] = "Tcircle"; + psod_glyphs[0x1E70] = "Tcircumflexbelow"; + psod_glyphs[0x0162] = "Tcommaaccent"; + psod_glyphs[0x1E6A] = "Tdotaccent"; + psod_glyphs[0x1E6C] = "Tdotbelow"; + psod_glyphs[0x0422] = "Tecyrillic"; + psod_glyphs[0x04AC] = "Tedescendercyrillic"; + psod_glyphs[0x2169] = "Tenroman"; + psod_glyphs[0x04B4] = "Tetsecyrillic"; + psod_glyphs[0x0398] = "Theta"; + psod_glyphs[0x01AC] = "Thook"; + psod_glyphs[0x00DE] = "Thorn"; + psod_glyphs[0xF7FE] = "Thornsmall"; + psod_glyphs[0x2162] = "Threeroman"; + psod_glyphs[0xF6FE] = "Tildesmall"; + psod_glyphs[0x054F] = "Tiwnarmenian"; + psod_glyphs[0x1E6E] = "Tlinebelow"; + psod_glyphs[0xFF34] = "Tmonospace"; + psod_glyphs[0x0539] = "Toarmenian"; + psod_glyphs[0x01BC] = "Tonefive"; + psod_glyphs[0x0184] = "Tonesix"; + psod_glyphs[0x01A7] = "Tonetwo"; + psod_glyphs[0x01AE] = "Tretroflexhook"; + psod_glyphs[0x0426] = "Tsecyrillic"; + psod_glyphs[0x040B] = "Tshecyrillic"; + psod_glyphs[0xF774] = "Tsmall"; + psod_glyphs[0x216B] = "Twelveroman"; + psod_glyphs[0x2161] = "Tworoman"; + psod_glyphs[0x0055] = "U"; + psod_glyphs[0x00DA] = "Uacute"; + psod_glyphs[0xF7FA] = "Uacutesmall"; + psod_glyphs[0x016C] = "Ubreve"; + psod_glyphs[0x01D3] = "Ucaron"; + psod_glyphs[0x24CA] = "Ucircle"; + psod_glyphs[0x00DB] = "Ucircumflex"; + psod_glyphs[0x1E76] = "Ucircumflexbelow"; + psod_glyphs[0xF7FB] = "Ucircumflexsmall"; + psod_glyphs[0x0423] = "Ucyrillic"; + psod_glyphs[0x0170] = "Udblacute"; + psod_glyphs[0x0214] = "Udblgrave"; + psod_glyphs[0x00DC] = "Udieresis"; + psod_glyphs[0x01D7] = "Udieresisacute"; + psod_glyphs[0x1E72] = "Udieresisbelow"; + psod_glyphs[0x01D9] = "Udieresiscaron"; + psod_glyphs[0x04F0] = "Udieresiscyrillic"; + psod_glyphs[0x01DB] = "Udieresisgrave"; + psod_glyphs[0x01D5] = "Udieresismacron"; + psod_glyphs[0xF7FC] = "Udieresissmall"; + psod_glyphs[0x1EE4] = "Udotbelow"; + psod_glyphs[0x00D9] = "Ugrave"; + psod_glyphs[0xF7F9] = "Ugravesmall"; + psod_glyphs[0x1EE6] = "Uhookabove"; + psod_glyphs[0x01AF] = "Uhorn"; + psod_glyphs[0x1EE8] = "Uhornacute"; + psod_glyphs[0x1EF0] = "Uhorndotbelow"; + psod_glyphs[0x1EEA] = "Uhorngrave"; + psod_glyphs[0x1EEC] = "Uhornhookabove"; + psod_glyphs[0x1EEE] = "Uhorntilde"; + psod_glyphs[0x0170] = "Uhungarumlaut"; + psod_glyphs[0x04F2] = "Uhungarumlautcyrillic"; + psod_glyphs[0x0216] = "Uinvertedbreve"; + psod_glyphs[0x0478] = "Ukcyrillic"; + psod_glyphs[0x016A] = "Umacron"; + psod_glyphs[0x04EE] = "Umacroncyrillic"; + psod_glyphs[0x1E7A] = "Umacrondieresis"; + psod_glyphs[0xFF35] = "Umonospace"; + psod_glyphs[0x0172] = "Uogonek"; + psod_glyphs[0x03A5] = "Upsilon"; + psod_glyphs[0x03D2] = "Upsilon1"; + psod_glyphs[0x03D3] = "Upsilonacutehooksymbolgreek"; + psod_glyphs[0x01B1] = "Upsilonafrican"; + psod_glyphs[0x03AB] = "Upsilondieresis"; + psod_glyphs[0x03D4] = "Upsilondieresishooksymbolgreek"; + psod_glyphs[0x03D2] = "Upsilonhooksymbol"; + psod_glyphs[0x038E] = "Upsilontonos"; + psod_glyphs[0x016E] = "Uring"; + psod_glyphs[0x040E] = "Ushortcyrillic"; + psod_glyphs[0xF775] = "Usmall"; + psod_glyphs[0x04AE] = "Ustraightcyrillic"; + psod_glyphs[0x04B0] = "Ustraightstrokecyrillic"; + psod_glyphs[0x0168] = "Utilde"; + psod_glyphs[0x1E78] = "Utildeacute"; + psod_glyphs[0x1E74] = "Utildebelow"; + psod_glyphs[0x0056] = "V"; + psod_glyphs[0x24CB] = "Vcircle"; + psod_glyphs[0x1E7E] = "Vdotbelow"; + psod_glyphs[0x0412] = "Vecyrillic"; + psod_glyphs[0x054E] = "Vewarmenian"; + psod_glyphs[0x01B2] = "Vhook"; + psod_glyphs[0xFF36] = "Vmonospace"; + psod_glyphs[0x0548] = "Voarmenian"; + psod_glyphs[0xF776] = "Vsmall"; + psod_glyphs[0x1E7C] = "Vtilde"; + psod_glyphs[0x0057] = "W"; + psod_glyphs[0x1E82] = "Wacute"; + psod_glyphs[0x24CC] = "Wcircle"; + psod_glyphs[0x0174] = "Wcircumflex"; + psod_glyphs[0x1E84] = "Wdieresis"; + psod_glyphs[0x1E86] = "Wdotaccent"; + psod_glyphs[0x1E88] = "Wdotbelow"; + psod_glyphs[0x1E80] = "Wgrave"; + psod_glyphs[0xFF37] = "Wmonospace"; + psod_glyphs[0xF777] = "Wsmall"; + psod_glyphs[0x0058] = "X"; + psod_glyphs[0x24CD] = "Xcircle"; + psod_glyphs[0x1E8C] = "Xdieresis"; + psod_glyphs[0x1E8A] = "Xdotaccent"; + psod_glyphs[0x053D] = "Xeharmenian"; + psod_glyphs[0x039E] = "Xi"; + psod_glyphs[0xFF38] = "Xmonospace"; + psod_glyphs[0xF778] = "Xsmall"; + psod_glyphs[0x0059] = "Y"; + psod_glyphs[0x00DD] = "Yacute"; + psod_glyphs[0xF7FD] = "Yacutesmall"; + psod_glyphs[0x0462] = "Yatcyrillic"; + psod_glyphs[0x24CE] = "Ycircle"; + psod_glyphs[0x0176] = "Ycircumflex"; + psod_glyphs[0x0178] = "Ydieresis"; + psod_glyphs[0xF7FF] = "Ydieresissmall"; + psod_glyphs[0x1E8E] = "Ydotaccent"; + psod_glyphs[0x1EF4] = "Ydotbelow"; + psod_glyphs[0x042B] = "Yericyrillic"; + psod_glyphs[0x04F8] = "Yerudieresiscyrillic"; + psod_glyphs[0x1EF2] = "Ygrave"; + psod_glyphs[0x01B3] = "Yhook"; + psod_glyphs[0x1EF6] = "Yhookabove"; + psod_glyphs[0x0545] = "Yiarmenian"; + psod_glyphs[0x0407] = "Yicyrillic"; + psod_glyphs[0x0552] = "Yiwnarmenian"; + psod_glyphs[0xFF39] = "Ymonospace"; + psod_glyphs[0xF779] = "Ysmall"; + psod_glyphs[0x1EF8] = "Ytilde"; + psod_glyphs[0x046A] = "Yusbigcyrillic"; + psod_glyphs[0x046C] = "Yusbigiotifiedcyrillic"; + psod_glyphs[0x0466] = "Yuslittlecyrillic"; + psod_glyphs[0x0468] = "Yuslittleiotifiedcyrillic"; + psod_glyphs[0x005A] = "Z"; + psod_glyphs[0x0536] = "Zaarmenian"; + psod_glyphs[0x0179] = "Zacute"; + psod_glyphs[0x017D] = "Zcaron"; + psod_glyphs[0xF6FF] = "Zcaronsmall"; + psod_glyphs[0x24CF] = "Zcircle"; + psod_glyphs[0x1E90] = "Zcircumflex"; + psod_glyphs[0x017B] = "Zdot"; + psod_glyphs[0x017B] = "Zdotaccent"; + psod_glyphs[0x1E92] = "Zdotbelow"; + psod_glyphs[0x0417] = "Zecyrillic"; + psod_glyphs[0x0498] = "Zedescendercyrillic"; + psod_glyphs[0x04DE] = "Zedieresiscyrillic"; + psod_glyphs[0x0396] = "Zeta"; + psod_glyphs[0x053A] = "Zhearmenian"; + psod_glyphs[0x04C1] = "Zhebrevecyrillic"; + psod_glyphs[0x0416] = "Zhecyrillic"; + psod_glyphs[0x0496] = "Zhedescendercyrillic"; + psod_glyphs[0x04DC] = "Zhedieresiscyrillic"; + psod_glyphs[0x1E94] = "Zlinebelow"; + psod_glyphs[0xFF3A] = "Zmonospace"; + psod_glyphs[0xF77A] = "Zsmall"; + psod_glyphs[0x01B5] = "Zstroke"; + psod_glyphs[0x0061] = "a"; + psod_glyphs[0x0986] = "aabengali"; + psod_glyphs[0x00E1] = "aacute"; + psod_glyphs[0x0906] = "aadeva"; + psod_glyphs[0x0A86] = "aagujarati"; + psod_glyphs[0x0A06] = "aagurmukhi"; + psod_glyphs[0x0A3E] = "aamatragurmukhi"; + psod_glyphs[0x3303] = "aarusquare"; + psod_glyphs[0x09BE] = "aavowelsignbengali"; + psod_glyphs[0x093E] = "aavowelsigndeva"; + psod_glyphs[0x0ABE] = "aavowelsigngujarati"; + psod_glyphs[0x055F] = "abbreviationmarkarmenian"; + psod_glyphs[0x0970] = "abbreviationsigndeva"; + psod_glyphs[0x0985] = "abengali"; + psod_glyphs[0x311A] = "abopomofo"; + psod_glyphs[0x0103] = "abreve"; + psod_glyphs[0x1EAF] = "abreveacute"; + psod_glyphs[0x04D1] = "abrevecyrillic"; + psod_glyphs[0x1EB7] = "abrevedotbelow"; + psod_glyphs[0x1EB1] = "abrevegrave"; + psod_glyphs[0x1EB3] = "abrevehookabove"; + psod_glyphs[0x1EB5] = "abrevetilde"; + psod_glyphs[0x01CE] = "acaron"; + psod_glyphs[0x24D0] = "acircle"; + psod_glyphs[0x00E2] = "acircumflex"; + psod_glyphs[0x1EA5] = "acircumflexacute"; + psod_glyphs[0x1EAD] = "acircumflexdotbelow"; + psod_glyphs[0x1EA7] = "acircumflexgrave"; + psod_glyphs[0x1EA9] = "acircumflexhookabove"; + psod_glyphs[0x1EAB] = "acircumflextilde"; + psod_glyphs[0x00B4] = "acute"; + psod_glyphs[0x0317] = "acutebelowcmb"; + psod_glyphs[0x0301] = "acutecmb"; + psod_glyphs[0x0301] = "acutecomb"; + psod_glyphs[0x0954] = "acutedeva"; + psod_glyphs[0x02CF] = "acutelowmod"; + psod_glyphs[0x0341] = "acutetonecmb"; + psod_glyphs[0x0430] = "acyrillic"; + psod_glyphs[0x0201] = "adblgrave"; + psod_glyphs[0x0A71] = "addakgurmukhi"; + psod_glyphs[0x0905] = "adeva"; + psod_glyphs[0x00E4] = "adieresis"; + psod_glyphs[0x04D3] = "adieresiscyrillic"; + psod_glyphs[0x01DF] = "adieresismacron"; + psod_glyphs[0x1EA1] = "adotbelow"; + psod_glyphs[0x01E1] = "adotmacron"; + psod_glyphs[0x00E6] = "ae"; + psod_glyphs[0x01FD] = "aeacute"; + psod_glyphs[0x3150] = "aekorean"; + psod_glyphs[0x01E3] = "aemacron"; + //psod_glyphs[0x2015] = "afii00208"; + //psod_glyphs[0x20A4] = "afii08941"; + //psod_glyphs[0x0410] = "afii10017"; + //psod_glyphs[0x0411] = "afii10018"; + //psod_glyphs[0x0412] = "afii10019"; + //psod_glyphs[0x0413] = "afii10020"; + //psod_glyphs[0x0414] = "afii10021"; + //psod_glyphs[0x0415] = "afii10022"; + //psod_glyphs[0x0401] = "afii10023"; + //psod_glyphs[0x0416] = "afii10024"; + //psod_glyphs[0x0417] = "afii10025"; + //psod_glyphs[0x0418] = "afii10026"; + //psod_glyphs[0x0419] = "afii10027"; + //psod_glyphs[0x041A] = "afii10028"; + //psod_glyphs[0x041B] = "afii10029"; + //psod_glyphs[0x041C] = "afii10030"; + //psod_glyphs[0x041D] = "afii10031"; + //psod_glyphs[0x041E] = "afii10032"; + //psod_glyphs[0x041F] = "afii10033"; + //psod_glyphs[0x0420] = "afii10034"; + //psod_glyphs[0x0421] = "afii10035"; + //psod_glyphs[0x0422] = "afii10036"; + //psod_glyphs[0x0423] = "afii10037"; + //psod_glyphs[0x0424] = "afii10038"; + //psod_glyphs[0x0425] = "afii10039"; + //psod_glyphs[0x0426] = "afii10040"; + //psod_glyphs[0x0427] = "afii10041"; + //psod_glyphs[0x0428] = "afii10042"; + //psod_glyphs[0x0429] = "afii10043"; + //psod_glyphs[0x042A] = "afii10044"; + //psod_glyphs[0x042B] = "afii10045"; + //psod_glyphs[0x042C] = "afii10046"; + //psod_glyphs[0x042D] = "afii10047"; + //psod_glyphs[0x042E] = "afii10048"; + //psod_glyphs[0x042F] = "afii10049"; + //psod_glyphs[0x0490] = "afii10050"; + //psod_glyphs[0x0402] = "afii10051"; + //psod_glyphs[0x0403] = "afii10052"; + //psod_glyphs[0x0404] = "afii10053"; + //psod_glyphs[0x0405] = "afii10054"; + //psod_glyphs[0x0406] = "afii10055"; + //psod_glyphs[0x0407] = "afii10056"; + //psod_glyphs[0x0408] = "afii10057"; + //psod_glyphs[0x0409] = "afii10058"; + //psod_glyphs[0x040A] = "afii10059"; + //psod_glyphs[0x040B] = "afii10060"; + //psod_glyphs[0x040C] = "afii10061"; + //psod_glyphs[0x040E] = "afii10062"; + //psod_glyphs[0xF6C4] = "afii10063"; + //psod_glyphs[0xF6C5] = "afii10064"; + //psod_glyphs[0x0430] = "afii10065"; + //psod_glyphs[0x0431] = "afii10066"; + //psod_glyphs[0x0432] = "afii10067"; + //psod_glyphs[0x0433] = "afii10068"; + //psod_glyphs[0x0434] = "afii10069"; + //psod_glyphs[0x0435] = "afii10070"; + //psod_glyphs[0x0451] = "afii10071"; + //psod_glyphs[0x0436] = "afii10072"; + //psod_glyphs[0x0437] = "afii10073"; + //psod_glyphs[0x0438] = "afii10074"; + //psod_glyphs[0x0439] = "afii10075"; + //psod_glyphs[0x043A] = "afii10076"; + //psod_glyphs[0x043B] = "afii10077"; + //psod_glyphs[0x043C] = "afii10078"; + //psod_glyphs[0x043D] = "afii10079"; + //psod_glyphs[0x043E] = "afii10080"; + //psod_glyphs[0x043F] = "afii10081"; + //psod_glyphs[0x0440] = "afii10082"; + //psod_glyphs[0x0441] = "afii10083"; + //psod_glyphs[0x0442] = "afii10084"; + //psod_glyphs[0x0443] = "afii10085"; + //psod_glyphs[0x0444] = "afii10086"; + //psod_glyphs[0x0445] = "afii10087"; + //psod_glyphs[0x0446] = "afii10088"; + //psod_glyphs[0x0447] = "afii10089"; + //psod_glyphs[0x0448] = "afii10090"; + //psod_glyphs[0x0449] = "afii10091"; + //psod_glyphs[0x044A] = "afii10092"; + //psod_glyphs[0x044B] = "afii10093"; + //psod_glyphs[0x044C] = "afii10094"; + //psod_glyphs[0x044D] = "afii10095"; + //psod_glyphs[0x044E] = "afii10096"; + //psod_glyphs[0x044F] = "afii10097"; + //psod_glyphs[0x0491] = "afii10098"; + //psod_glyphs[0x0452] = "afii10099"; + //psod_glyphs[0x0453] = "afii10100"; + //psod_glyphs[0x0454] = "afii10101"; + //psod_glyphs[0x0455] = "afii10102"; + //psod_glyphs[0x0456] = "afii10103"; + //psod_glyphs[0x0457] = "afii10104"; + //psod_glyphs[0x0458] = "afii10105"; + //psod_glyphs[0x0459] = "afii10106"; + //psod_glyphs[0x045A] = "afii10107"; + //psod_glyphs[0x045B] = "afii10108"; + //psod_glyphs[0x045C] = "afii10109"; + //psod_glyphs[0x045E] = "afii10110"; + //psod_glyphs[0x040F] = "afii10145"; + //psod_glyphs[0x0462] = "afii10146"; + //psod_glyphs[0x0472] = "afii10147"; + //psod_glyphs[0x0474] = "afii10148"; + //psod_glyphs[0xF6C6] = "afii10192"; + //psod_glyphs[0x045F] = "afii10193"; + //psod_glyphs[0x0463] = "afii10194"; + //psod_glyphs[0x0473] = "afii10195"; + //psod_glyphs[0x0475] = "afii10196"; + //psod_glyphs[0xF6C7] = "afii10831"; + //psod_glyphs[0xF6C8] = "afii10832"; + //psod_glyphs[0x04D9] = "afii10846"; + //psod_glyphs[0x200E] = "afii299"; + //psod_glyphs[0x200F] = "afii300"; + //psod_glyphs[0x200D] = "afii301"; + //psod_glyphs[0x066A] = "afii57381"; + //psod_glyphs[0x060C] = "afii57388"; + //psod_glyphs[0x0660] = "afii57392"; + //psod_glyphs[0x0661] = "afii57393"; + //psod_glyphs[0x0662] = "afii57394"; + //psod_glyphs[0x0663] = "afii57395"; + //psod_glyphs[0x0664] = "afii57396"; + //psod_glyphs[0x0665] = "afii57397"; + //psod_glyphs[0x0666] = "afii57398"; + //psod_glyphs[0x0667] = "afii57399"; + //psod_glyphs[0x0668] = "afii57400"; + //psod_glyphs[0x0669] = "afii57401"; + //psod_glyphs[0x061B] = "afii57403"; + //psod_glyphs[0x061F] = "afii57407"; + //psod_glyphs[0x0621] = "afii57409"; + //psod_glyphs[0x0622] = "afii57410"; + //psod_glyphs[0x0623] = "afii57411"; + //psod_glyphs[0x0624] = "afii57412"; + //psod_glyphs[0x0625] = "afii57413"; + //psod_glyphs[0x0626] = "afii57414"; + //psod_glyphs[0x0627] = "afii57415"; + //psod_glyphs[0x0628] = "afii57416"; + //psod_glyphs[0x0629] = "afii57417"; + //psod_glyphs[0x062A] = "afii57418"; + //psod_glyphs[0x062B] = "afii57419"; + //psod_glyphs[0x062C] = "afii57420"; + //psod_glyphs[0x062D] = "afii57421"; + //psod_glyphs[0x062E] = "afii57422"; + //psod_glyphs[0x062F] = "afii57423"; + //psod_glyphs[0x0630] = "afii57424"; + //psod_glyphs[0x0631] = "afii57425"; + //psod_glyphs[0x0632] = "afii57426"; + //psod_glyphs[0x0633] = "afii57427"; + //psod_glyphs[0x0634] = "afii57428"; + //psod_glyphs[0x0635] = "afii57429"; + //psod_glyphs[0x0636] = "afii57430"; + //psod_glyphs[0x0637] = "afii57431"; + //psod_glyphs[0x0638] = "afii57432"; + //psod_glyphs[0x0639] = "afii57433"; + //psod_glyphs[0x063A] = "afii57434"; + //psod_glyphs[0x0640] = "afii57440"; + //psod_glyphs[0x0641] = "afii57441"; + //psod_glyphs[0x0642] = "afii57442"; + //psod_glyphs[0x0643] = "afii57443"; + //psod_glyphs[0x0644] = "afii57444"; + //psod_glyphs[0x0645] = "afii57445"; + //psod_glyphs[0x0646] = "afii57446"; + //psod_glyphs[0x0648] = "afii57448"; + //psod_glyphs[0x0649] = "afii57449"; + //psod_glyphs[0x064A] = "afii57450"; + //psod_glyphs[0x064B] = "afii57451"; + //psod_glyphs[0x064C] = "afii57452"; + //psod_glyphs[0x064D] = "afii57453"; + //psod_glyphs[0x064E] = "afii57454"; + //psod_glyphs[0x064F] = "afii57455"; + //psod_glyphs[0x0650] = "afii57456"; + //psod_glyphs[0x0651] = "afii57457"; + //psod_glyphs[0x0652] = "afii57458"; + //psod_glyphs[0x0647] = "afii57470"; + //psod_glyphs[0x06A4] = "afii57505"; + //psod_glyphs[0x067E] = "afii57506"; + //psod_glyphs[0x0686] = "afii57507"; + //psod_glyphs[0x0698] = "afii57508"; + //psod_glyphs[0x06AF] = "afii57509"; + //psod_glyphs[0x0679] = "afii57511"; + //psod_glyphs[0x0688] = "afii57512"; + //psod_glyphs[0x0691] = "afii57513"; + //psod_glyphs[0x06BA] = "afii57514"; + //psod_glyphs[0x06D2] = "afii57519"; + //psod_glyphs[0x06D5] = "afii57534"; + //psod_glyphs[0x20AA] = "afii57636"; + //psod_glyphs[0x05BE] = "afii57645"; + //psod_glyphs[0x05C3] = "afii57658"; + //psod_glyphs[0x05D0] = "afii57664"; + //psod_glyphs[0x05D1] = "afii57665"; + //psod_glyphs[0x05D2] = "afii57666"; + //psod_glyphs[0x05D3] = "afii57667"; + //psod_glyphs[0x05D4] = "afii57668"; + //psod_glyphs[0x05D5] = "afii57669"; + //psod_glyphs[0x05D6] = "afii57670"; + //psod_glyphs[0x05D7] = "afii57671"; + //psod_glyphs[0x05D8] = "afii57672"; + //psod_glyphs[0x05D9] = "afii57673"; + //psod_glyphs[0x05DA] = "afii57674"; + //psod_glyphs[0x05DB] = "afii57675"; + //psod_glyphs[0x05DC] = "afii57676"; + //psod_glyphs[0x05DD] = "afii57677"; + //psod_glyphs[0x05DE] = "afii57678"; + //psod_glyphs[0x05DF] = "afii57679"; + //psod_glyphs[0x05E0] = "afii57680"; + //psod_glyphs[0x05E1] = "afii57681"; + //psod_glyphs[0x05E2] = "afii57682"; + //psod_glyphs[0x05E3] = "afii57683"; + //psod_glyphs[0x05E4] = "afii57684"; + //psod_glyphs[0x05E5] = "afii57685"; + //psod_glyphs[0x05E6] = "afii57686"; + //psod_glyphs[0x05E7] = "afii57687"; + //psod_glyphs[0x05E8] = "afii57688"; + //psod_glyphs[0x05E9] = "afii57689"; + //psod_glyphs[0x05EA] = "afii57690"; + //psod_glyphs[0xFB2A] = "afii57694"; + //psod_glyphs[0xFB2B] = "afii57695"; + //psod_glyphs[0xFB4B] = "afii57700"; + //psod_glyphs[0xFB1F] = "afii57705"; + //psod_glyphs[0x05F0] = "afii57716"; + //psod_glyphs[0x05F1] = "afii57717"; + //psod_glyphs[0x05F2] = "afii57718"; + //psod_glyphs[0xFB35] = "afii57723"; + //psod_glyphs[0x05B4] = "afii57793"; + //psod_glyphs[0x05B5] = "afii57794"; + //psod_glyphs[0x05B6] = "afii57795"; + //psod_glyphs[0x05BB] = "afii57796"; + //psod_glyphs[0x05B8] = "afii57797"; + //psod_glyphs[0x05B7] = "afii57798"; + //psod_glyphs[0x05B0] = "afii57799"; + //psod_glyphs[0x05B2] = "afii57800"; + //psod_glyphs[0x05B1] = "afii57801"; + //psod_glyphs[0x05B3] = "afii57802"; + //psod_glyphs[0x05C2] = "afii57803"; + //psod_glyphs[0x05C1] = "afii57804"; + //psod_glyphs[0x05B9] = "afii57806"; + //psod_glyphs[0x05BC] = "afii57807"; + //psod_glyphs[0x05BD] = "afii57839"; + //psod_glyphs[0x05BF] = "afii57841"; + //psod_glyphs[0x05C0] = "afii57842"; + //psod_glyphs[0x02BC] = "afii57929"; + //psod_glyphs[0x2105] = "afii61248"; + //psod_glyphs[0x2113] = "afii61289"; + //psod_glyphs[0x2116] = "afii61352"; + //psod_glyphs[0x202C] = "afii61573"; + //psod_glyphs[0x202D] = "afii61574"; + //psod_glyphs[0x202E] = "afii61575"; + //psod_glyphs[0x200C] = "afii61664"; + //psod_glyphs[0x066D] = "afii63167"; + //psod_glyphs[0x02BD] = "afii64937"; + psod_glyphs[0x00E0] = "agrave"; + psod_glyphs[0x0A85] = "agujarati"; + psod_glyphs[0x0A05] = "agurmukhi"; + psod_glyphs[0x3042] = "ahiragana"; + psod_glyphs[0x1EA3] = "ahookabove"; + psod_glyphs[0x0990] = "aibengali"; + psod_glyphs[0x311E] = "aibopomofo"; + psod_glyphs[0x0910] = "aideva"; + psod_glyphs[0x04D5] = "aiecyrillic"; + psod_glyphs[0x0A90] = "aigujarati"; + psod_glyphs[0x0A10] = "aigurmukhi"; + psod_glyphs[0x0A48] = "aimatragurmukhi"; + psod_glyphs[0x0639] = "ainarabic"; + psod_glyphs[0xFECA] = "ainfinalarabic"; + psod_glyphs[0xFECB] = "aininitialarabic"; + psod_glyphs[0xFECC] = "ainmedialarabic"; + psod_glyphs[0x0203] = "ainvertedbreve"; + psod_glyphs[0x09C8] = "aivowelsignbengali"; + psod_glyphs[0x0948] = "aivowelsigndeva"; + psod_glyphs[0x0AC8] = "aivowelsigngujarati"; + psod_glyphs[0x30A2] = "akatakana"; + psod_glyphs[0xFF71] = "akatakanahalfwidth"; + psod_glyphs[0x314F] = "akorean"; + psod_glyphs[0x05D0] = "alef"; + psod_glyphs[0x0627] = "alefarabic"; + psod_glyphs[0xFB30] = "alefdageshhebrew"; + psod_glyphs[0xFE8E] = "aleffinalarabic"; + psod_glyphs[0x0623] = "alefhamzaabovearabic"; + psod_glyphs[0xFE84] = "alefhamzaabovefinalarabic"; + psod_glyphs[0x0625] = "alefhamzabelowarabic"; + psod_glyphs[0xFE88] = "alefhamzabelowfinalarabic"; + psod_glyphs[0x05D0] = "alefhebrew"; + psod_glyphs[0xFB4F] = "aleflamedhebrew"; + psod_glyphs[0x0622] = "alefmaddaabovearabic"; + psod_glyphs[0xFE82] = "alefmaddaabovefinalarabic"; + psod_glyphs[0x0649] = "alefmaksuraarabic"; + psod_glyphs[0xFEF0] = "alefmaksurafinalarabic"; + psod_glyphs[0xFEF3] = "alefmaksurainitialarabic"; + psod_glyphs[0xFEF4] = "alefmaksuramedialarabic"; + psod_glyphs[0xFB2E] = "alefpatahhebrew"; + psod_glyphs[0xFB2F] = "alefqamatshebrew"; + psod_glyphs[0x2135] = "aleph"; + psod_glyphs[0x224C] = "allequal"; + psod_glyphs[0x03B1] = "alpha"; + psod_glyphs[0x03AC] = "alphatonos"; + psod_glyphs[0x0101] = "amacron"; + psod_glyphs[0xFF41] = "amonospace"; + psod_glyphs[0x0026] = "ampersand"; + psod_glyphs[0xFF06] = "ampersandmonospace"; + psod_glyphs[0xF726] = "ampersandsmall"; + psod_glyphs[0x33C2] = "amsquare"; + psod_glyphs[0x3122] = "anbopomofo"; + psod_glyphs[0x3124] = "angbopomofo"; + psod_glyphs[0x0E5A] = "angkhankhuthai"; + psod_glyphs[0x2220] = "angle"; + psod_glyphs[0x3008] = "anglebracketleft"; + psod_glyphs[0xFE3F] = "anglebracketleftvertical"; + psod_glyphs[0x3009] = "anglebracketright"; + psod_glyphs[0xFE40] = "anglebracketrightvertical"; + psod_glyphs[0x2329] = "angleleft"; + psod_glyphs[0x232A] = "angleright"; + psod_glyphs[0x212B] = "angstrom"; + psod_glyphs[0x0387] = "anoteleia"; + psod_glyphs[0x0952] = "anudattadeva"; + psod_glyphs[0x0982] = "anusvarabengali"; + psod_glyphs[0x0902] = "anusvaradeva"; + psod_glyphs[0x0A82] = "anusvaragujarati"; + psod_glyphs[0x0105] = "aogonek"; + psod_glyphs[0x3300] = "apaatosquare"; + psod_glyphs[0x249C] = "aparen"; + psod_glyphs[0x055A] = "apostrophearmenian"; + psod_glyphs[0x02BC] = "apostrophemod"; + psod_glyphs[0xF8FF] = "apple"; + psod_glyphs[0x2250] = "approaches"; + psod_glyphs[0x2248] = "approxequal"; + psod_glyphs[0x2252] = "approxequalorimage"; + psod_glyphs[0x2245] = "approximatelyequal"; + psod_glyphs[0x318E] = "araeaekorean"; + psod_glyphs[0x318D] = "araeakorean"; + psod_glyphs[0x2312] = "arc"; + psod_glyphs[0x1E9A] = "arighthalfring"; + psod_glyphs[0x00E5] = "aring"; + psod_glyphs[0x01FB] = "aringacute"; + psod_glyphs[0x1E01] = "aringbelow"; + psod_glyphs[0x2194] = "arrowboth"; + psod_glyphs[0x21E3] = "arrowdashdown"; + psod_glyphs[0x21E0] = "arrowdashleft"; + psod_glyphs[0x21E2] = "arrowdashright"; + psod_glyphs[0x21E1] = "arrowdashup"; + psod_glyphs[0x21D4] = "arrowdblboth"; + psod_glyphs[0x21D3] = "arrowdbldown"; + psod_glyphs[0x21D0] = "arrowdblleft"; + psod_glyphs[0x21D2] = "arrowdblright"; + psod_glyphs[0x21D1] = "arrowdblup"; + psod_glyphs[0x2193] = "arrowdown"; + psod_glyphs[0x2199] = "arrowdownleft"; + psod_glyphs[0x2198] = "arrowdownright"; + psod_glyphs[0x21E9] = "arrowdownwhite"; + psod_glyphs[0x02C5] = "arrowheaddownmod"; + psod_glyphs[0x02C2] = "arrowheadleftmod"; + psod_glyphs[0x02C3] = "arrowheadrightmod"; + psod_glyphs[0x02C4] = "arrowheadupmod"; + psod_glyphs[0xF8E7] = "arrowhorizex"; + psod_glyphs[0x2190] = "arrowleft"; + psod_glyphs[0x21D0] = "arrowleftdbl"; + psod_glyphs[0x21CD] = "arrowleftdblstroke"; + psod_glyphs[0x21C6] = "arrowleftoverright"; + psod_glyphs[0x21E6] = "arrowleftwhite"; + psod_glyphs[0x2192] = "arrowright"; + psod_glyphs[0x21CF] = "arrowrightdblstroke"; + psod_glyphs[0x279E] = "arrowrightheavy"; + psod_glyphs[0x21C4] = "arrowrightoverleft"; + psod_glyphs[0x21E8] = "arrowrightwhite"; + psod_glyphs[0x21E4] = "arrowtableft"; + psod_glyphs[0x21E5] = "arrowtabright"; + psod_glyphs[0x2191] = "arrowup"; + psod_glyphs[0x2195] = "arrowupdn"; + psod_glyphs[0x21A8] = "arrowupdnbse"; + psod_glyphs[0x21A8] = "arrowupdownbase"; + psod_glyphs[0x2196] = "arrowupleft"; + psod_glyphs[0x21C5] = "arrowupleftofdown"; + psod_glyphs[0x2197] = "arrowupright"; + psod_glyphs[0x21E7] = "arrowupwhite"; + psod_glyphs[0xF8E6] = "arrowvertex"; + psod_glyphs[0x005E] = "asciicircum"; + psod_glyphs[0xFF3E] = "asciicircummonospace"; + psod_glyphs[0x007E] = "asciitilde"; + psod_glyphs[0xFF5E] = "asciitildemonospace"; + psod_glyphs[0x0251] = "ascript"; + psod_glyphs[0x0252] = "ascriptturned"; + psod_glyphs[0x3041] = "asmallhiragana"; + psod_glyphs[0x30A1] = "asmallkatakana"; + psod_glyphs[0xFF67] = "asmallkatakanahalfwidth"; + psod_glyphs[0x002A] = "asterisk"; + psod_glyphs[0x066D] = "asteriskaltonearabic"; + psod_glyphs[0x066D] = "asteriskarabic"; + psod_glyphs[0x2217] = "asteriskmath"; + psod_glyphs[0xFF0A] = "asteriskmonospace"; + psod_glyphs[0xFE61] = "asterisksmall"; + psod_glyphs[0x2042] = "asterism"; + psod_glyphs[0xF6E9] = "asuperior"; + psod_glyphs[0x2243] = "asymptoticallyequal"; + psod_glyphs[0x0040] = "at"; + psod_glyphs[0x00E3] = "atilde"; + psod_glyphs[0xFF20] = "atmonospace"; + psod_glyphs[0xFE6B] = "atsmall"; + psod_glyphs[0x0250] = "aturned"; + psod_glyphs[0x0994] = "aubengali"; + psod_glyphs[0x3120] = "aubopomofo"; + psod_glyphs[0x0914] = "audeva"; + psod_glyphs[0x0A94] = "augujarati"; + psod_glyphs[0x0A14] = "augurmukhi"; + psod_glyphs[0x09D7] = "aulengthmarkbengali"; + psod_glyphs[0x0A4C] = "aumatragurmukhi"; + psod_glyphs[0x09CC] = "auvowelsignbengali"; + psod_glyphs[0x094C] = "auvowelsigndeva"; + psod_glyphs[0x0ACC] = "auvowelsigngujarati"; + psod_glyphs[0x093D] = "avagrahadeva"; + psod_glyphs[0x0561] = "aybarmenian"; + psod_glyphs[0x05E2] = "ayin"; + psod_glyphs[0xFB20] = "ayinaltonehebrew"; + psod_glyphs[0x05E2] = "ayinhebrew"; + psod_glyphs[0x0062] = "b"; + psod_glyphs[0x09AC] = "babengali"; + psod_glyphs[0x005C] = "backslash"; + psod_glyphs[0xFF3C] = "backslashmonospace"; + psod_glyphs[0x092C] = "badeva"; + psod_glyphs[0x0AAC] = "bagujarati"; + psod_glyphs[0x0A2C] = "bagurmukhi"; + psod_glyphs[0x3070] = "bahiragana"; + psod_glyphs[0x0E3F] = "bahtthai"; + psod_glyphs[0x30D0] = "bakatakana"; + psod_glyphs[0x007C] = "bar"; + psod_glyphs[0xFF5C] = "barmonospace"; + psod_glyphs[0x3105] = "bbopomofo"; + psod_glyphs[0x24D1] = "bcircle"; + psod_glyphs[0x1E03] = "bdotaccent"; + psod_glyphs[0x1E05] = "bdotbelow"; + psod_glyphs[0x266C] = "beamedsixteenthnotes"; + psod_glyphs[0x2235] = "because"; + psod_glyphs[0x0431] = "becyrillic"; + psod_glyphs[0x0628] = "beharabic"; + psod_glyphs[0xFE90] = "behfinalarabic"; + psod_glyphs[0xFE91] = "behinitialarabic"; + psod_glyphs[0x3079] = "behiragana"; + psod_glyphs[0xFE92] = "behmedialarabic"; + psod_glyphs[0xFC9F] = "behmeeminitialarabic"; + psod_glyphs[0xFC08] = "behmeemisolatedarabic"; + psod_glyphs[0xFC6D] = "behnoonfinalarabic"; + psod_glyphs[0x30D9] = "bekatakana"; + psod_glyphs[0x0562] = "benarmenian"; + psod_glyphs[0x05D1] = "bet"; + psod_glyphs[0x03B2] = "beta"; + psod_glyphs[0x03D0] = "betasymbolgreek"; + psod_glyphs[0xFB31] = "betdagesh"; + psod_glyphs[0xFB31] = "betdageshhebrew"; + psod_glyphs[0x05D1] = "bethebrew"; + psod_glyphs[0xFB4C] = "betrafehebrew"; + psod_glyphs[0x09AD] = "bhabengali"; + psod_glyphs[0x092D] = "bhadeva"; + psod_glyphs[0x0AAD] = "bhagujarati"; + psod_glyphs[0x0A2D] = "bhagurmukhi"; + psod_glyphs[0x0253] = "bhook"; + psod_glyphs[0x3073] = "bihiragana"; + psod_glyphs[0x30D3] = "bikatakana"; + psod_glyphs[0x0298] = "bilabialclick"; + psod_glyphs[0x0A02] = "bindigurmukhi"; + psod_glyphs[0x3331] = "birusquare"; + psod_glyphs[0x25CF] = "blackcircle"; + psod_glyphs[0x25C6] = "blackdiamond"; + psod_glyphs[0x25BC] = "blackdownpointingtriangle"; + psod_glyphs[0x25C4] = "blackleftpointingpointer"; + psod_glyphs[0x25C0] = "blackleftpointingtriangle"; + psod_glyphs[0x3010] = "blacklenticularbracketleft"; + psod_glyphs[0xFE3B] = "blacklenticularbracketleftvertical"; + psod_glyphs[0x3011] = "blacklenticularbracketright"; + psod_glyphs[0xFE3C] = "blacklenticularbracketrightvertical"; + psod_glyphs[0x25E3] = "blacklowerlefttriangle"; + psod_glyphs[0x25E2] = "blacklowerrighttriangle"; + psod_glyphs[0x25AC] = "blackrectangle"; + psod_glyphs[0x25BA] = "blackrightpointingpointer"; + psod_glyphs[0x25B6] = "blackrightpointingtriangle"; + psod_glyphs[0x25AA] = "blacksmallsquare"; + psod_glyphs[0x263B] = "blacksmilingface"; + psod_glyphs[0x25A0] = "blacksquare"; + psod_glyphs[0x2605] = "blackstar"; + psod_glyphs[0x25E4] = "blackupperlefttriangle"; + psod_glyphs[0x25E5] = "blackupperrighttriangle"; + psod_glyphs[0x25B4] = "blackuppointingsmalltriangle"; + psod_glyphs[0x25B2] = "blackuppointingtriangle"; + psod_glyphs[0x2423] = "blank"; + psod_glyphs[0x1E07] = "blinebelow"; + psod_glyphs[0x2588] = "block"; + psod_glyphs[0xFF42] = "bmonospace"; + psod_glyphs[0x0E1A] = "bobaimaithai"; + psod_glyphs[0x307C] = "bohiragana"; + psod_glyphs[0x30DC] = "bokatakana"; + psod_glyphs[0x249D] = "bparen"; + psod_glyphs[0x33C3] = "bqsquare"; + psod_glyphs[0xF8F4] = "braceex"; + psod_glyphs[0x007B] = "braceleft"; + psod_glyphs[0xF8F3] = "braceleftbt"; + psod_glyphs[0xF8F2] = "braceleftmid"; + psod_glyphs[0xFF5B] = "braceleftmonospace"; + psod_glyphs[0xFE5B] = "braceleftsmall"; + psod_glyphs[0xF8F1] = "bracelefttp"; + psod_glyphs[0xFE37] = "braceleftvertical"; + psod_glyphs[0x007D] = "braceright"; + psod_glyphs[0xF8FE] = "bracerightbt"; + psod_glyphs[0xF8FD] = "bracerightmid"; + psod_glyphs[0xFF5D] = "bracerightmonospace"; + psod_glyphs[0xFE5C] = "bracerightsmall"; + psod_glyphs[0xF8FC] = "bracerighttp"; + psod_glyphs[0xFE38] = "bracerightvertical"; + psod_glyphs[0x005B] = "bracketleft"; + psod_glyphs[0xF8F0] = "bracketleftbt"; + psod_glyphs[0xF8EF] = "bracketleftex"; + psod_glyphs[0xFF3B] = "bracketleftmonospace"; + psod_glyphs[0xF8EE] = "bracketlefttp"; + psod_glyphs[0x005D] = "bracketright"; + psod_glyphs[0xF8FB] = "bracketrightbt"; + psod_glyphs[0xF8FA] = "bracketrightex"; + psod_glyphs[0xFF3D] = "bracketrightmonospace"; + psod_glyphs[0xF8F9] = "bracketrighttp"; + psod_glyphs[0x02D8] = "breve"; + psod_glyphs[0x032E] = "brevebelowcmb"; + psod_glyphs[0x0306] = "brevecmb"; + psod_glyphs[0x032F] = "breveinvertedbelowcmb"; + psod_glyphs[0x0311] = "breveinvertedcmb"; + psod_glyphs[0x0361] = "breveinverteddoublecmb"; + psod_glyphs[0x032A] = "bridgebelowcmb"; + psod_glyphs[0x033A] = "bridgeinvertedbelowcmb"; + psod_glyphs[0x00A6] = "brokenbar"; + psod_glyphs[0x0180] = "bstroke"; + psod_glyphs[0xF6EA] = "bsuperior"; + psod_glyphs[0x0183] = "btopbar"; + psod_glyphs[0x3076] = "buhiragana"; + psod_glyphs[0x30D6] = "bukatakana"; + psod_glyphs[0x2022] = "bullet"; + psod_glyphs[0x25D8] = "bulletinverse"; + psod_glyphs[0x2219] = "bulletoperator"; + psod_glyphs[0x25CE] = "bullseye"; + psod_glyphs[0x0063] = "c"; + psod_glyphs[0x056E] = "caarmenian"; + psod_glyphs[0x099A] = "cabengali"; + psod_glyphs[0x0107] = "cacute"; + psod_glyphs[0x091A] = "cadeva"; + psod_glyphs[0x0A9A] = "cagujarati"; + psod_glyphs[0x0A1A] = "cagurmukhi"; + psod_glyphs[0x3388] = "calsquare"; + psod_glyphs[0x0981] = "candrabindubengali"; + psod_glyphs[0x0310] = "candrabinducmb"; + psod_glyphs[0x0901] = "candrabindudeva"; + psod_glyphs[0x0A81] = "candrabindugujarati"; + psod_glyphs[0x21EA] = "capslock"; + psod_glyphs[0x2105] = "careof"; + psod_glyphs[0x02C7] = "caron"; + psod_glyphs[0x032C] = "caronbelowcmb"; + psod_glyphs[0x030C] = "caroncmb"; + psod_glyphs[0x21B5] = "carriagereturn"; + psod_glyphs[0x3118] = "cbopomofo"; + psod_glyphs[0x010D] = "ccaron"; + psod_glyphs[0x00E7] = "ccedilla"; + psod_glyphs[0x1E09] = "ccedillaacute"; + psod_glyphs[0x24D2] = "ccircle"; + psod_glyphs[0x0109] = "ccircumflex"; + psod_glyphs[0x0255] = "ccurl"; + psod_glyphs[0x010B] = "cdot"; + psod_glyphs[0x010B] = "cdotaccent"; + psod_glyphs[0x33C5] = "cdsquare"; + psod_glyphs[0x00B8] = "cedilla"; + psod_glyphs[0x0327] = "cedillacmb"; + psod_glyphs[0x00A2] = "cent"; + psod_glyphs[0x2103] = "centigrade"; + psod_glyphs[0xF6DF] = "centinferior"; + psod_glyphs[0xFFE0] = "centmonospace"; + psod_glyphs[0xF7A2] = "centoldstyle"; + psod_glyphs[0xF6E0] = "centsuperior"; + psod_glyphs[0x0579] = "chaarmenian"; + psod_glyphs[0x099B] = "chabengali"; + psod_glyphs[0x091B] = "chadeva"; + psod_glyphs[0x0A9B] = "chagujarati"; + psod_glyphs[0x0A1B] = "chagurmukhi"; + psod_glyphs[0x3114] = "chbopomofo"; + psod_glyphs[0x04BD] = "cheabkhasiancyrillic"; + psod_glyphs[0x2713] = "checkmark"; + psod_glyphs[0x0447] = "checyrillic"; + psod_glyphs[0x04BF] = "chedescenderabkhasiancyrillic"; + psod_glyphs[0x04B7] = "chedescendercyrillic"; + psod_glyphs[0x04F5] = "chedieresiscyrillic"; + psod_glyphs[0x0573] = "cheharmenian"; + psod_glyphs[0x04CC] = "chekhakassiancyrillic"; + psod_glyphs[0x04B9] = "cheverticalstrokecyrillic"; + psod_glyphs[0x03C7] = "chi"; + psod_glyphs[0x3277] = "chieuchacirclekorean"; + psod_glyphs[0x3217] = "chieuchaparenkorean"; + psod_glyphs[0x3269] = "chieuchcirclekorean"; + psod_glyphs[0x314A] = "chieuchkorean"; + psod_glyphs[0x3209] = "chieuchparenkorean"; + psod_glyphs[0x0E0A] = "chochangthai"; + psod_glyphs[0x0E08] = "chochanthai"; + psod_glyphs[0x0E09] = "chochingthai"; + psod_glyphs[0x0E0C] = "chochoethai"; + psod_glyphs[0x0188] = "chook"; + psod_glyphs[0x3276] = "cieucacirclekorean"; + psod_glyphs[0x3216] = "cieucaparenkorean"; + psod_glyphs[0x3268] = "cieuccirclekorean"; + psod_glyphs[0x3148] = "cieuckorean"; + psod_glyphs[0x3208] = "cieucparenkorean"; + psod_glyphs[0x321C] = "cieucuparenkorean"; + psod_glyphs[0x25CB] = "circle"; + psod_glyphs[0x2297] = "circlemultiply"; + psod_glyphs[0x2299] = "circleot"; + psod_glyphs[0x2295] = "circleplus"; + psod_glyphs[0x3036] = "circlepostalmark"; + psod_glyphs[0x25D0] = "circlewithlefthalfblack"; + psod_glyphs[0x25D1] = "circlewithrighthalfblack"; + psod_glyphs[0x02C6] = "circumflex"; + psod_glyphs[0x032D] = "circumflexbelowcmb"; + psod_glyphs[0x0302] = "circumflexcmb"; + psod_glyphs[0x2327] = "clear"; + psod_glyphs[0x01C2] = "clickalveolar"; + psod_glyphs[0x01C0] = "clickdental"; + psod_glyphs[0x01C1] = "clicklateral"; + psod_glyphs[0x01C3] = "clickretroflex"; + psod_glyphs[0x2663] = "club"; + psod_glyphs[0x2663] = "clubsuitblack"; + psod_glyphs[0x2667] = "clubsuitwhite"; + psod_glyphs[0x33A4] = "cmcubedsquare"; + psod_glyphs[0xFF43] = "cmonospace"; + psod_glyphs[0x33A0] = "cmsquaredsquare"; + psod_glyphs[0x0581] = "coarmenian"; + psod_glyphs[0x003A] = "colon"; + psod_glyphs[0x20A1] = "colonmonetary"; + psod_glyphs[0xFF1A] = "colonmonospace"; + psod_glyphs[0x20A1] = "colonsign"; + psod_glyphs[0xFE55] = "colonsmall"; + psod_glyphs[0x02D1] = "colontriangularhalfmod"; + psod_glyphs[0x02D0] = "colontriangularmod"; + psod_glyphs[0x002C] = "comma"; + psod_glyphs[0x0313] = "commaabovecmb"; + psod_glyphs[0x0315] = "commaaboverightcmb"; + psod_glyphs[0xF6C3] = "commaaccent"; + psod_glyphs[0x060C] = "commaarabic"; + psod_glyphs[0x055D] = "commaarmenian"; + psod_glyphs[0xF6E1] = "commainferior"; + psod_glyphs[0xFF0C] = "commamonospace"; + psod_glyphs[0x0314] = "commareversedabovecmb"; + psod_glyphs[0x02BD] = "commareversedmod"; + psod_glyphs[0xFE50] = "commasmall"; + psod_glyphs[0xF6E2] = "commasuperior"; + psod_glyphs[0x0312] = "commaturnedabovecmb"; + psod_glyphs[0x02BB] = "commaturnedmod"; + psod_glyphs[0x263C] = "compass"; + psod_glyphs[0x2245] = "congruent"; + psod_glyphs[0x222E] = "contourintegral"; + psod_glyphs[0x2303] = "control"; + psod_glyphs[0x0006] = "controlACK"; + psod_glyphs[0x0007] = "controlBEL"; + psod_glyphs[0x0008] = "controlBS"; + psod_glyphs[0x0018] = "controlCAN"; + psod_glyphs[0x000D] = "controlCR"; + psod_glyphs[0x0011] = "controlDC1"; + psod_glyphs[0x0012] = "controlDC2"; + psod_glyphs[0x0013] = "controlDC3"; + psod_glyphs[0x0014] = "controlDC4"; + psod_glyphs[0x007F] = "controlDEL"; + psod_glyphs[0x0010] = "controlDLE"; + psod_glyphs[0x0019] = "controlEM"; + psod_glyphs[0x0005] = "controlENQ"; + psod_glyphs[0x0004] = "controlEOT"; + psod_glyphs[0x001B] = "controlESC"; + psod_glyphs[0x0017] = "controlETB"; + psod_glyphs[0x0003] = "controlETX"; + psod_glyphs[0x000C] = "controlFF"; + psod_glyphs[0x001C] = "controlFS"; + psod_glyphs[0x001D] = "controlGS"; + psod_glyphs[0x0009] = "controlHT"; + psod_glyphs[0x000A] = "controlLF"; + psod_glyphs[0x0015] = "controlNAK"; + psod_glyphs[0x001E] = "controlRS"; + psod_glyphs[0x000F] = "controlSI"; + psod_glyphs[0x000E] = "controlSO"; + psod_glyphs[0x0002] = "controlSOT"; + psod_glyphs[0x0001] = "controlSTX"; + psod_glyphs[0x001A] = "controlSUB"; + psod_glyphs[0x0016] = "controlSYN"; + psod_glyphs[0x001F] = "controlUS"; + psod_glyphs[0x000B] = "controlVT"; + psod_glyphs[0x00A9] = "copyright"; + psod_glyphs[0xF8E9] = "copyrightsans"; + psod_glyphs[0xF6D9] = "copyrightserif"; + psod_glyphs[0x300C] = "cornerbracketleft"; + psod_glyphs[0xFF62] = "cornerbracketlefthalfwidth"; + psod_glyphs[0xFE41] = "cornerbracketleftvertical"; + psod_glyphs[0x300D] = "cornerbracketright"; + psod_glyphs[0xFF63] = "cornerbracketrighthalfwidth"; + psod_glyphs[0xFE42] = "cornerbracketrightvertical"; + psod_glyphs[0x337F] = "corporationsquare"; + psod_glyphs[0x33C7] = "cosquare"; + psod_glyphs[0x33C6] = "coverkgsquare"; + psod_glyphs[0x249E] = "cparen"; + psod_glyphs[0x20A2] = "cruzeiro"; + psod_glyphs[0x0297] = "cstretched"; + psod_glyphs[0x22CF] = "curlyand"; + psod_glyphs[0x22CE] = "curlyor"; + psod_glyphs[0x00A4] = "currency"; + psod_glyphs[0xF6D1] = "cyrBreve"; + psod_glyphs[0xF6D2] = "cyrFlex"; + psod_glyphs[0xF6D4] = "cyrbreve"; + psod_glyphs[0xF6D5] = "cyrflex"; + psod_glyphs[0x0064] = "d"; + psod_glyphs[0x0564] = "daarmenian"; + psod_glyphs[0x09A6] = "dabengali"; + psod_glyphs[0x0636] = "dadarabic"; + psod_glyphs[0x0926] = "dadeva"; + psod_glyphs[0xFEBE] = "dadfinalarabic"; + psod_glyphs[0xFEBF] = "dadinitialarabic"; + psod_glyphs[0xFEC0] = "dadmedialarabic"; + psod_glyphs[0x05BC] = "dagesh"; + //psod_glyphs[0x05BC] = "dageshhebrew"; + psod_glyphs[0x2020] = "dagger"; + psod_glyphs[0x2021] = "daggerdbl"; + psod_glyphs[0x0AA6] = "dagujarati"; + psod_glyphs[0x0A26] = "dagurmukhi"; + psod_glyphs[0x3060] = "dahiragana"; + psod_glyphs[0x30C0] = "dakatakana"; + psod_glyphs[0x062F] = "dalarabic"; + psod_glyphs[0x05D3] = "dalet"; + psod_glyphs[0xFB33] = "daletdagesh"; + psod_glyphs[0xFB33] = "daletdageshhebrew"; + //psod_glyphs[0x05D3 05B2] = "dalethatafpatah"; + //psod_glyphs[0x05D3 05B2] = "dalethatafpatahhebrew"; + //psod_glyphs[0x05D3 05B1] = "dalethatafsegol"; + //psod_glyphs[0x05D3 05B1] = "dalethatafsegolhebrew"; + psod_glyphs[0x05D3] = "dalethebrew"; + //psod_glyphs[0x05D3 05B4] = "dalethiriq"; + //psod_glyphs[0x05D3 05B4] = "dalethiriqhebrew"; + //psod_glyphs[0x05D3 05B9] = "daletholam"; + //psod_glyphs[0x05D3 05B9] = "daletholamhebrew"; + //psod_glyphs[0x05D3 05B7] = "daletpatah"; + //psod_glyphs[0x05D3 05B7] = "daletpatahhebrew"; + //psod_glyphs[0x05D3 05B8] = "daletqamats"; + //psod_glyphs[0x05D3 05B8] = "daletqamatshebrew"; + //psod_glyphs[0x05D3 05BB] = "daletqubuts"; + //psod_glyphs[0x05D3 05BB] = "daletqubutshebrew"; + //psod_glyphs[0x05D3 05B6] = "daletsegol"; + //psod_glyphs[0x05D3 05B6] = "daletsegolhebrew"; + //psod_glyphs[0x05D3 05B0] = "daletsheva"; + //psod_glyphs[0x05D3 05B0] = "daletshevahebrew"; + //psod_glyphs[0x05D3 05B5] = "dalettsere"; + //psod_glyphs[0x05D3 05B5] = "dalettserehebrew"; + psod_glyphs[0xFEAA] = "dalfinalarabic"; + psod_glyphs[0x064F] = "dammaarabic"; + psod_glyphs[0x064F] = "dammalowarabic"; + psod_glyphs[0x064C] = "dammatanaltonearabic"; + psod_glyphs[0x064C] = "dammatanarabic"; + psod_glyphs[0x0964] = "danda"; + psod_glyphs[0x05A7] = "dargahebrew"; + psod_glyphs[0x05A7] = "dargalefthebrew"; + psod_glyphs[0x0485] = "dasiapneumatacyrilliccmb"; + psod_glyphs[0xF6D3] = "dblGrave"; + psod_glyphs[0x300A] = "dblanglebracketleft"; + psod_glyphs[0xFE3D] = "dblanglebracketleftvertical"; + psod_glyphs[0x300B] = "dblanglebracketright"; + psod_glyphs[0xFE3E] = "dblanglebracketrightvertical"; + psod_glyphs[0x032B] = "dblarchinvertedbelowcmb"; + psod_glyphs[0x21D4] = "dblarrowleft"; + psod_glyphs[0x21D2] = "dblarrowright"; + psod_glyphs[0x0965] = "dbldanda"; + psod_glyphs[0xF6D6] = "dblgrave"; + psod_glyphs[0x030F] = "dblgravecmb"; + psod_glyphs[0x222C] = "dblintegral"; + psod_glyphs[0x2017] = "dbllowline"; + psod_glyphs[0x0333] = "dbllowlinecmb"; + psod_glyphs[0x033F] = "dbloverlinecmb"; + psod_glyphs[0x02BA] = "dblprimemod"; + psod_glyphs[0x2016] = "dblverticalbar"; + psod_glyphs[0x030E] = "dblverticallineabovecmb"; + psod_glyphs[0x3109] = "dbopomofo"; + psod_glyphs[0x33C8] = "dbsquare"; + psod_glyphs[0x010F] = "dcaron"; + psod_glyphs[0x1E11] = "dcedilla"; + psod_glyphs[0x24D3] = "dcircle"; + psod_glyphs[0x1E13] = "dcircumflexbelow"; + psod_glyphs[0x0111] = "dcroat"; + psod_glyphs[0x09A1] = "ddabengali"; + psod_glyphs[0x0921] = "ddadeva"; + psod_glyphs[0x0AA1] = "ddagujarati"; + psod_glyphs[0x0A21] = "ddagurmukhi"; + psod_glyphs[0x0688] = "ddalarabic"; + psod_glyphs[0xFB89] = "ddalfinalarabic"; + psod_glyphs[0x095C] = "dddhadeva"; + psod_glyphs[0x09A2] = "ddhabengali"; + psod_glyphs[0x0922] = "ddhadeva"; + psod_glyphs[0x0AA2] = "ddhagujarati"; + psod_glyphs[0x0A22] = "ddhagurmukhi"; + psod_glyphs[0x1E0B] = "ddotaccent"; + psod_glyphs[0x1E0D] = "ddotbelow"; + psod_glyphs[0x066B] = "decimalseparatorarabic"; + psod_glyphs[0x066B] = "decimalseparatorpersian"; + psod_glyphs[0x0434] = "decyrillic"; + psod_glyphs[0x00B0] = "degree"; + psod_glyphs[0x05AD] = "dehihebrew"; + psod_glyphs[0x3067] = "dehiragana"; + psod_glyphs[0x03EF] = "deicoptic"; + psod_glyphs[0x30C7] = "dekatakana"; + psod_glyphs[0x232B] = "deleteleft"; + psod_glyphs[0x2326] = "deleteright"; + psod_glyphs[0x03B4] = "delta"; + psod_glyphs[0x018D] = "deltaturned"; + psod_glyphs[0x09F8] = "denominatorminusonenumeratorbengali"; + psod_glyphs[0x02A4] = "dezh"; + psod_glyphs[0x09A7] = "dhabengali"; + psod_glyphs[0x0927] = "dhadeva"; + psod_glyphs[0x0AA7] = "dhagujarati"; + psod_glyphs[0x0A27] = "dhagurmukhi"; + psod_glyphs[0x0257] = "dhook"; + psod_glyphs[0x0385] = "dialytikatonos"; + psod_glyphs[0x0344] = "dialytikatonoscmb"; + psod_glyphs[0x2666] = "diamond"; + psod_glyphs[0x2662] = "diamondsuitwhite"; + psod_glyphs[0x00A8] = "dieresis"; + psod_glyphs[0xF6D7] = "dieresisacute"; + psod_glyphs[0x0324] = "dieresisbelowcmb"; + psod_glyphs[0x0308] = "dieresiscmb"; + psod_glyphs[0xF6D8] = "dieresisgrave"; + psod_glyphs[0x0385] = "dieresistonos"; + psod_glyphs[0x3062] = "dihiragana"; + psod_glyphs[0x30C2] = "dikatakana"; + psod_glyphs[0x3003] = "dittomark"; + psod_glyphs[0x00F7] = "divide"; + psod_glyphs[0x2223] = "divides"; + psod_glyphs[0x2215] = "divisionslash"; + psod_glyphs[0x0452] = "djecyrillic"; + psod_glyphs[0x2593] = "dkshade"; + psod_glyphs[0x1E0F] = "dlinebelow"; + psod_glyphs[0x3397] = "dlsquare"; + psod_glyphs[0x0111] = "dmacron"; + psod_glyphs[0xFF44] = "dmonospace"; + psod_glyphs[0x2584] = "dnblock"; + psod_glyphs[0x0E0E] = "dochadathai"; + psod_glyphs[0x0E14] = "dodekthai"; + psod_glyphs[0x3069] = "dohiragana"; + psod_glyphs[0x30C9] = "dokatakana"; + psod_glyphs[0x0024] = "dollar"; + psod_glyphs[0xF6E3] = "dollarinferior"; + psod_glyphs[0xFF04] = "dollarmonospace"; + psod_glyphs[0xF724] = "dollaroldstyle"; + psod_glyphs[0xFE69] = "dollarsmall"; + psod_glyphs[0xF6E4] = "dollarsuperior"; + psod_glyphs[0x20AB] = "dong"; + psod_glyphs[0x3326] = "dorusquare"; + psod_glyphs[0x02D9] = "dotaccent"; + psod_glyphs[0x0307] = "dotaccentcmb"; + psod_glyphs[0x0323] = "dotbelowcmb"; + psod_glyphs[0x0323] = "dotbelowcomb"; + psod_glyphs[0x30FB] = "dotkatakana"; + psod_glyphs[0x0131] = "dotlessi"; + psod_glyphs[0xF6BE] = "dotlessj"; + psod_glyphs[0x0284] = "dotlessjstrokehook"; + psod_glyphs[0x22C5] = "dotmath"; + psod_glyphs[0x25CC] = "dottedcircle"; + psod_glyphs[0xFB1F] = "doubleyodpatah"; + psod_glyphs[0xFB1F] = "doubleyodpatahhebrew"; + psod_glyphs[0x031E] = "downtackbelowcmb"; + psod_glyphs[0x02D5] = "downtackmod"; + psod_glyphs[0x249F] = "dparen"; + psod_glyphs[0xF6EB] = "dsuperior"; + psod_glyphs[0x0256] = "dtail"; + psod_glyphs[0x018C] = "dtopbar"; + psod_glyphs[0x3065] = "duhiragana"; + psod_glyphs[0x30C5] = "dukatakana"; + psod_glyphs[0x01F3] = "dz"; + psod_glyphs[0x02A3] = "dzaltone"; + psod_glyphs[0x01C6] = "dzcaron"; + psod_glyphs[0x02A5] = "dzcurl"; + psod_glyphs[0x04E1] = "dzeabkhasiancyrillic"; + psod_glyphs[0x0455] = "dzecyrillic"; + psod_glyphs[0x045F] = "dzhecyrillic"; + psod_glyphs[0x0065] = "e"; + psod_glyphs[0x00E9] = "eacute"; + psod_glyphs[0x2641] = "earth"; + psod_glyphs[0x098F] = "ebengali"; + psod_glyphs[0x311C] = "ebopomofo"; + psod_glyphs[0x0115] = "ebreve"; + psod_glyphs[0x090D] = "ecandradeva"; + psod_glyphs[0x0A8D] = "ecandragujarati"; + psod_glyphs[0x0945] = "ecandravowelsigndeva"; + psod_glyphs[0x0AC5] = "ecandravowelsigngujarati"; + psod_glyphs[0x011B] = "ecaron"; + psod_glyphs[0x1E1D] = "ecedillabreve"; + psod_glyphs[0x0565] = "echarmenian"; + psod_glyphs[0x0587] = "echyiwnarmenian"; + psod_glyphs[0x24D4] = "ecircle"; + psod_glyphs[0x00EA] = "ecircumflex"; + psod_glyphs[0x1EBF] = "ecircumflexacute"; + psod_glyphs[0x1E19] = "ecircumflexbelow"; + psod_glyphs[0x1EC7] = "ecircumflexdotbelow"; + psod_glyphs[0x1EC1] = "ecircumflexgrave"; + psod_glyphs[0x1EC3] = "ecircumflexhookabove"; + psod_glyphs[0x1EC5] = "ecircumflextilde"; + psod_glyphs[0x0454] = "ecyrillic"; + psod_glyphs[0x0205] = "edblgrave"; + psod_glyphs[0x090F] = "edeva"; + psod_glyphs[0x00EB] = "edieresis"; + psod_glyphs[0x0117] = "edot"; + psod_glyphs[0x0117] = "edotaccent"; + psod_glyphs[0x1EB9] = "edotbelow"; + psod_glyphs[0x0A0F] = "eegurmukhi"; + psod_glyphs[0x0A47] = "eematragurmukhi"; + psod_glyphs[0x0444] = "efcyrillic"; + psod_glyphs[0x00E8] = "egrave"; + psod_glyphs[0x0A8F] = "egujarati"; + psod_glyphs[0x0567] = "eharmenian"; + psod_glyphs[0x311D] = "ehbopomofo"; + psod_glyphs[0x3048] = "ehiragana"; + psod_glyphs[0x1EBB] = "ehookabove"; + psod_glyphs[0x311F] = "eibopomofo"; + psod_glyphs[0x0038] = "eight"; + psod_glyphs[0x0668] = "eightarabic"; + psod_glyphs[0x09EE] = "eightbengali"; + psod_glyphs[0x2467] = "eightcircle"; + psod_glyphs[0x2791] = "eightcircleinversesansserif"; + psod_glyphs[0x096E] = "eightdeva"; + psod_glyphs[0x2471] = "eighteencircle"; + psod_glyphs[0x2485] = "eighteenparen"; + psod_glyphs[0x2499] = "eighteenperiod"; + psod_glyphs[0x0AEE] = "eightgujarati"; + psod_glyphs[0x0A6E] = "eightgurmukhi"; + psod_glyphs[0x0668] = "eighthackarabic"; + psod_glyphs[0x3028] = "eighthangzhou"; + psod_glyphs[0x266B] = "eighthnotebeamed"; + psod_glyphs[0x3227] = "eightideographicparen"; + psod_glyphs[0x2088] = "eightinferior"; + psod_glyphs[0xFF18] = "eightmonospace"; + psod_glyphs[0xF738] = "eightoldstyle"; + psod_glyphs[0x247B] = "eightparen"; + psod_glyphs[0x248F] = "eightperiod"; + psod_glyphs[0x06F8] = "eightpersian"; + psod_glyphs[0x2177] = "eightroman"; + psod_glyphs[0x2078] = "eightsuperior"; + psod_glyphs[0x0E58] = "eightthai"; + psod_glyphs[0x0207] = "einvertedbreve"; + psod_glyphs[0x0465] = "eiotifiedcyrillic"; + psod_glyphs[0x30A8] = "ekatakana"; + psod_glyphs[0xFF74] = "ekatakanahalfwidth"; + psod_glyphs[0x0A74] = "ekonkargurmukhi"; + psod_glyphs[0x3154] = "ekorean"; + psod_glyphs[0x043B] = "elcyrillic"; + psod_glyphs[0x2208] = "element"; + psod_glyphs[0x246A] = "elevencircle"; + psod_glyphs[0x247E] = "elevenparen"; + psod_glyphs[0x2492] = "elevenperiod"; + psod_glyphs[0x217A] = "elevenroman"; + psod_glyphs[0x2026] = "ellipsis"; + psod_glyphs[0x22EE] = "ellipsisvertical"; + psod_glyphs[0x0113] = "emacron"; + psod_glyphs[0x1E17] = "emacronacute"; + psod_glyphs[0x1E15] = "emacrongrave"; + psod_glyphs[0x043C] = "emcyrillic"; + psod_glyphs[0x2014] = "emdash"; + psod_glyphs[0xFE31] = "emdashvertical"; + psod_glyphs[0xFF45] = "emonospace"; + psod_glyphs[0x055B] = "emphasismarkarmenian"; + psod_glyphs[0x2205] = "emptyset"; + psod_glyphs[0x3123] = "enbopomofo"; + psod_glyphs[0x043D] = "encyrillic"; + psod_glyphs[0x2013] = "endash"; + psod_glyphs[0xFE32] = "endashvertical"; + psod_glyphs[0x04A3] = "endescendercyrillic"; + psod_glyphs[0x014B] = "eng"; + psod_glyphs[0x3125] = "engbopomofo"; + psod_glyphs[0x04A5] = "enghecyrillic"; + psod_glyphs[0x04C8] = "enhookcyrillic"; + psod_glyphs[0x2002] = "enspace"; + psod_glyphs[0x0119] = "eogonek"; + psod_glyphs[0x3153] = "eokorean"; + psod_glyphs[0x025B] = "eopen"; + psod_glyphs[0x029A] = "eopenclosed"; + psod_glyphs[0x025C] = "eopenreversed"; + psod_glyphs[0x025E] = "eopenreversedclosed"; + psod_glyphs[0x025D] = "eopenreversedhook"; + psod_glyphs[0x24A0] = "eparen"; + psod_glyphs[0x03B5] = "epsilon"; + psod_glyphs[0x03AD] = "epsilontonos"; + psod_glyphs[0x003D] = "equal"; + psod_glyphs[0xFF1D] = "equalmonospace"; + psod_glyphs[0xFE66] = "equalsmall"; + psod_glyphs[0x207C] = "equalsuperior"; + psod_glyphs[0x2261] = "equivalence"; + psod_glyphs[0x3126] = "erbopomofo"; + psod_glyphs[0x0440] = "ercyrillic"; + psod_glyphs[0x0258] = "ereversed"; + psod_glyphs[0x044D] = "ereversedcyrillic"; + psod_glyphs[0x0441] = "escyrillic"; + psod_glyphs[0x04AB] = "esdescendercyrillic"; + psod_glyphs[0x0283] = "esh"; + psod_glyphs[0x0286] = "eshcurl"; + psod_glyphs[0x090E] = "eshortdeva"; + psod_glyphs[0x0946] = "eshortvowelsigndeva"; + psod_glyphs[0x01AA] = "eshreversedloop"; + psod_glyphs[0x0285] = "eshsquatreversed"; + psod_glyphs[0x3047] = "esmallhiragana"; + psod_glyphs[0x30A7] = "esmallkatakana"; + psod_glyphs[0xFF6A] = "esmallkatakanahalfwidth"; + psod_glyphs[0x212E] = "estimated"; + psod_glyphs[0xF6EC] = "esuperior"; + psod_glyphs[0x03B7] = "eta"; + psod_glyphs[0x0568] = "etarmenian"; + psod_glyphs[0x03AE] = "etatonos"; + psod_glyphs[0x00F0] = "eth"; + psod_glyphs[0x1EBD] = "etilde"; + psod_glyphs[0x1E1B] = "etildebelow"; + psod_glyphs[0x0591] = "etnahtafoukhhebrew"; + psod_glyphs[0x0591] = "etnahtafoukhlefthebrew"; + psod_glyphs[0x0591] = "etnahtahebrew"; + psod_glyphs[0x0591] = "etnahtalefthebrew"; + psod_glyphs[0x01DD] = "eturned"; + psod_glyphs[0x3161] = "eukorean"; + psod_glyphs[0x20AC] = "euro"; + psod_glyphs[0x09C7] = "evowelsignbengali"; + psod_glyphs[0x0947] = "evowelsigndeva"; + psod_glyphs[0x0AC7] = "evowelsigngujarati"; + psod_glyphs[0x0021] = "exclam"; + psod_glyphs[0x055C] = "exclamarmenian"; + psod_glyphs[0x203C] = "exclamdbl"; + psod_glyphs[0x00A1] = "exclamdown"; + psod_glyphs[0xF7A1] = "exclamdownsmall"; + psod_glyphs[0xFF01] = "exclammonospace"; + psod_glyphs[0xF721] = "exclamsmall"; + psod_glyphs[0x2203] = "existential"; + psod_glyphs[0x0292] = "ezh"; + psod_glyphs[0x01EF] = "ezhcaron"; + psod_glyphs[0x0293] = "ezhcurl"; + psod_glyphs[0x01B9] = "ezhreversed"; + psod_glyphs[0x01BA] = "ezhtail"; + psod_glyphs[0x0066] = "f"; + psod_glyphs[0x095E] = "fadeva"; + psod_glyphs[0x0A5E] = "fagurmukhi"; + psod_glyphs[0x2109] = "fahrenheit"; + psod_glyphs[0x064E] = "fathaarabic"; + psod_glyphs[0x064E] = "fathalowarabic"; + psod_glyphs[0x064B] = "fathatanarabic"; + psod_glyphs[0x3108] = "fbopomofo"; + psod_glyphs[0x24D5] = "fcircle"; + psod_glyphs[0x1E1F] = "fdotaccent"; + psod_glyphs[0x0641] = "feharabic"; + psod_glyphs[0x0586] = "feharmenian"; + psod_glyphs[0xFED2] = "fehfinalarabic"; + psod_glyphs[0xFED3] = "fehinitialarabic"; + psod_glyphs[0xFED4] = "fehmedialarabic"; + psod_glyphs[0x03E5] = "feicoptic"; + psod_glyphs[0x2640] = "female"; + psod_glyphs[0xFB00] = "ff"; + psod_glyphs[0xFB03] = "ffi"; + psod_glyphs[0xFB04] = "ffl"; + psod_glyphs[0xFB01] = "fi"; + psod_glyphs[0x246E] = "fifteencircle"; + psod_glyphs[0x2482] = "fifteenparen"; + psod_glyphs[0x2496] = "fifteenperiod"; + psod_glyphs[0x2012] = "figuredash"; + psod_glyphs[0x25A0] = "filledbox"; + psod_glyphs[0x25AC] = "filledrect"; + psod_glyphs[0x05DA] = "finalkaf"; + psod_glyphs[0xFB3A] = "finalkafdagesh"; + psod_glyphs[0xFB3A] = "finalkafdageshhebrew"; + psod_glyphs[0x05DA] = "finalkafhebrew"; + //psod_glyphs[0x05DA 05B8] = "finalkafqamats"; + //psod_glyphs[0x05DA 05B8] = "finalkafqamatshebrew"; + //psod_glyphs[0x05DA 05B0] = "finalkafsheva"; + //psod_glyphs[0x05DA 05B0] = "finalkafshevahebrew"; + psod_glyphs[0x05DD] = "finalmem"; + psod_glyphs[0x05DD] = "finalmemhebrew"; + psod_glyphs[0x05DF] = "finalnun"; + psod_glyphs[0x05DF] = "finalnunhebrew"; + psod_glyphs[0x05E3] = "finalpe"; + psod_glyphs[0x05E3] = "finalpehebrew"; + psod_glyphs[0x05E5] = "finaltsadi"; + psod_glyphs[0x05E5] = "finaltsadihebrew"; + psod_glyphs[0x02C9] = "firsttonechinese"; + psod_glyphs[0x25C9] = "fisheye"; + psod_glyphs[0x0473] = "fitacyrillic"; + psod_glyphs[0x0035] = "five"; + psod_glyphs[0x0665] = "fivearabic"; + psod_glyphs[0x09EB] = "fivebengali"; + psod_glyphs[0x2464] = "fivecircle"; + psod_glyphs[0x278E] = "fivecircleinversesansserif"; + psod_glyphs[0x096B] = "fivedeva"; + psod_glyphs[0x215D] = "fiveeighths"; + psod_glyphs[0x0AEB] = "fivegujarati"; + psod_glyphs[0x0A6B] = "fivegurmukhi"; + psod_glyphs[0x0665] = "fivehackarabic"; + psod_glyphs[0x3025] = "fivehangzhou"; + psod_glyphs[0x3224] = "fiveideographicparen"; + psod_glyphs[0x2085] = "fiveinferior"; + psod_glyphs[0xFF15] = "fivemonospace"; + psod_glyphs[0xF735] = "fiveoldstyle"; + psod_glyphs[0x2478] = "fiveparen"; + psod_glyphs[0x248C] = "fiveperiod"; + psod_glyphs[0x06F5] = "fivepersian"; + psod_glyphs[0x2174] = "fiveroman"; + psod_glyphs[0x2075] = "fivesuperior"; + psod_glyphs[0x0E55] = "fivethai"; + psod_glyphs[0xFB02] = "fl"; + psod_glyphs[0x0192] = "florin"; + psod_glyphs[0xFF46] = "fmonospace"; + psod_glyphs[0x3399] = "fmsquare"; + psod_glyphs[0x0E1F] = "fofanthai"; + psod_glyphs[0x0E1D] = "fofathai"; + psod_glyphs[0x0E4F] = "fongmanthai"; + psod_glyphs[0x2200] = "forall"; + psod_glyphs[0x0034] = "four"; + psod_glyphs[0x0664] = "fourarabic"; + psod_glyphs[0x09EA] = "fourbengali"; + psod_glyphs[0x2463] = "fourcircle"; + psod_glyphs[0x278D] = "fourcircleinversesansserif"; + psod_glyphs[0x096A] = "fourdeva"; + psod_glyphs[0x0AEA] = "fourgujarati"; + psod_glyphs[0x0A6A] = "fourgurmukhi"; + psod_glyphs[0x0664] = "fourhackarabic"; + psod_glyphs[0x3024] = "fourhangzhou"; + psod_glyphs[0x3223] = "fourideographicparen"; + psod_glyphs[0x2084] = "fourinferior"; + psod_glyphs[0xFF14] = "fourmonospace"; + psod_glyphs[0x09F7] = "fournumeratorbengali"; + psod_glyphs[0xF734] = "fouroldstyle"; + psod_glyphs[0x2477] = "fourparen"; + psod_glyphs[0x248B] = "fourperiod"; + psod_glyphs[0x06F4] = "fourpersian"; + psod_glyphs[0x2173] = "fourroman"; + psod_glyphs[0x2074] = "foursuperior"; + psod_glyphs[0x246D] = "fourteencircle"; + psod_glyphs[0x2481] = "fourteenparen"; + psod_glyphs[0x2495] = "fourteenperiod"; + psod_glyphs[0x0E54] = "fourthai"; + psod_glyphs[0x02CB] = "fourthtonechinese"; + psod_glyphs[0x24A1] = "fparen"; + psod_glyphs[0x2044] = "fraction"; + psod_glyphs[0x20A3] = "franc"; + psod_glyphs[0x0067] = "g"; + psod_glyphs[0x0997] = "gabengali"; + psod_glyphs[0x01F5] = "gacute"; + psod_glyphs[0x0917] = "gadeva"; + psod_glyphs[0x06AF] = "gafarabic"; + psod_glyphs[0xFB93] = "gaffinalarabic"; + psod_glyphs[0xFB94] = "gafinitialarabic"; + psod_glyphs[0xFB95] = "gafmedialarabic"; + psod_glyphs[0x0A97] = "gagujarati"; + psod_glyphs[0x0A17] = "gagurmukhi"; + psod_glyphs[0x304C] = "gahiragana"; + psod_glyphs[0x30AC] = "gakatakana"; + psod_glyphs[0x03B3] = "gamma"; + psod_glyphs[0x0263] = "gammalatinsmall"; + psod_glyphs[0x02E0] = "gammasuperior"; + psod_glyphs[0x03EB] = "gangiacoptic"; + psod_glyphs[0x310D] = "gbopomofo"; + psod_glyphs[0x011F] = "gbreve"; + psod_glyphs[0x01E7] = "gcaron"; + psod_glyphs[0x0123] = "gcedilla"; + psod_glyphs[0x24D6] = "gcircle"; + psod_glyphs[0x011D] = "gcircumflex"; + psod_glyphs[0x0123] = "gcommaaccent"; + psod_glyphs[0x0121] = "gdot"; + psod_glyphs[0x0121] = "gdotaccent"; + psod_glyphs[0x0433] = "gecyrillic"; + psod_glyphs[0x3052] = "gehiragana"; + psod_glyphs[0x30B2] = "gekatakana"; + psod_glyphs[0x2251] = "geometricallyequal"; + psod_glyphs[0x059C] = "gereshaccenthebrew"; + psod_glyphs[0x05F3] = "gereshhebrew"; + psod_glyphs[0x059D] = "gereshmuqdamhebrew"; + psod_glyphs[0x00DF] = "germandbls"; + psod_glyphs[0x059E] = "gershayimaccenthebrew"; + psod_glyphs[0x05F4] = "gershayimhebrew"; + psod_glyphs[0x3013] = "getamark"; + psod_glyphs[0x0998] = "ghabengali"; + psod_glyphs[0x0572] = "ghadarmenian"; + psod_glyphs[0x0918] = "ghadeva"; + psod_glyphs[0x0A98] = "ghagujarati"; + psod_glyphs[0x0A18] = "ghagurmukhi"; + psod_glyphs[0x063A] = "ghainarabic"; + psod_glyphs[0xFECE] = "ghainfinalarabic"; + psod_glyphs[0xFECF] = "ghaininitialarabic"; + psod_glyphs[0xFED0] = "ghainmedialarabic"; + psod_glyphs[0x0495] = "ghemiddlehookcyrillic"; + psod_glyphs[0x0493] = "ghestrokecyrillic"; + psod_glyphs[0x0491] = "gheupturncyrillic"; + psod_glyphs[0x095A] = "ghhadeva"; + psod_glyphs[0x0A5A] = "ghhagurmukhi"; + psod_glyphs[0x0260] = "ghook"; + psod_glyphs[0x3393] = "ghzsquare"; + psod_glyphs[0x304E] = "gihiragana"; + psod_glyphs[0x30AE] = "gikatakana"; + psod_glyphs[0x0563] = "gimarmenian"; + psod_glyphs[0x05D2] = "gimel"; + psod_glyphs[0xFB32] = "gimeldagesh"; + psod_glyphs[0xFB32] = "gimeldageshhebrew"; + psod_glyphs[0x05D2] = "gimelhebrew"; + psod_glyphs[0x0453] = "gjecyrillic"; + psod_glyphs[0x01BE] = "glottalinvertedstroke"; + psod_glyphs[0x0294] = "glottalstop"; + psod_glyphs[0x0296] = "glottalstopinverted"; + psod_glyphs[0x02C0] = "glottalstopmod"; + psod_glyphs[0x0295] = "glottalstopreversed"; + psod_glyphs[0x02C1] = "glottalstopreversedmod"; + psod_glyphs[0x02E4] = "glottalstopreversedsuperior"; + psod_glyphs[0x02A1] = "glottalstopstroke"; + psod_glyphs[0x02A2] = "glottalstopstrokereversed"; + psod_glyphs[0x1E21] = "gmacron"; + psod_glyphs[0xFF47] = "gmonospace"; + psod_glyphs[0x3054] = "gohiragana"; + psod_glyphs[0x30B4] = "gokatakana"; + psod_glyphs[0x24A2] = "gparen"; + psod_glyphs[0x33AC] = "gpasquare"; + psod_glyphs[0x2207] = "gradient"; + psod_glyphs[0x0060] = "grave"; + psod_glyphs[0x0316] = "gravebelowcmb"; + psod_glyphs[0x0300] = "gravecmb"; + psod_glyphs[0x0300] = "gravecomb"; + psod_glyphs[0x0953] = "gravedeva"; + psod_glyphs[0x02CE] = "gravelowmod"; + psod_glyphs[0xFF40] = "gravemonospace"; + psod_glyphs[0x0340] = "gravetonecmb"; + psod_glyphs[0x003E] = "greater"; + psod_glyphs[0x2265] = "greaterequal"; + psod_glyphs[0x22DB] = "greaterequalorless"; + psod_glyphs[0xFF1E] = "greatermonospace"; + psod_glyphs[0x2273] = "greaterorequivalent"; + psod_glyphs[0x2277] = "greaterorless"; + psod_glyphs[0x2267] = "greateroverequal"; + psod_glyphs[0xFE65] = "greatersmall"; + psod_glyphs[0x0261] = "gscript"; + psod_glyphs[0x01E5] = "gstroke"; + psod_glyphs[0x3050] = "guhiragana"; + psod_glyphs[0x00AB] = "guillemotleft"; + psod_glyphs[0x00BB] = "guillemotright"; + psod_glyphs[0x2039] = "guilsinglleft"; + psod_glyphs[0x203A] = "guilsinglright"; + psod_glyphs[0x30B0] = "gukatakana"; + psod_glyphs[0x3318] = "guramusquare"; + psod_glyphs[0x33C9] = "gysquare"; + psod_glyphs[0x0068] = "h"; + psod_glyphs[0x04A9] = "haabkhasiancyrillic"; + psod_glyphs[0x06C1] = "haaltonearabic"; + psod_glyphs[0x09B9] = "habengali"; + psod_glyphs[0x04B3] = "hadescendercyrillic"; + psod_glyphs[0x0939] = "hadeva"; + psod_glyphs[0x0AB9] = "hagujarati"; + psod_glyphs[0x0A39] = "hagurmukhi"; + psod_glyphs[0x062D] = "haharabic"; + psod_glyphs[0xFEA2] = "hahfinalarabic"; + psod_glyphs[0xFEA3] = "hahinitialarabic"; + psod_glyphs[0x306F] = "hahiragana"; + psod_glyphs[0xFEA4] = "hahmedialarabic"; + psod_glyphs[0x332A] = "haitusquare"; + psod_glyphs[0x30CF] = "hakatakana"; + psod_glyphs[0xFF8A] = "hakatakanahalfwidth"; + psod_glyphs[0x0A4D] = "halantgurmukhi"; + psod_glyphs[0x0621] = "hamzaarabic"; + //psod_glyphs[0x0621 064F] = "hamzadammaarabic"; + //psod_glyphs[0x0621 064C] = "hamzadammatanarabic"; + //psod_glyphs[0x0621 064E] = "hamzafathaarabic"; + //psod_glyphs[0x0621 064B] = "hamzafathatanarabic"; + psod_glyphs[0x0621] = "hamzalowarabic"; + //psod_glyphs[0x0621 0650] = "hamzalowkasraarabic"; + //psod_glyphs[0x0621 064D] = "hamzalowkasratanarabic"; + //psod_glyphs[0x0621 0652] = "hamzasukunarabic"; + psod_glyphs[0x3164] = "hangulfiller"; + psod_glyphs[0x044A] = "hardsigncyrillic"; + psod_glyphs[0x21BC] = "harpoonleftbarbup"; + psod_glyphs[0x21C0] = "harpoonrightbarbup"; + psod_glyphs[0x33CA] = "hasquare"; + psod_glyphs[0x05B2] = "hatafpatah"; + //psod_glyphs[0x05B2] = "hatafpatah16"; + //psod_glyphs[0x05B2] = "hatafpatah23"; + //psod_glyphs[0x05B2] = "hatafpatah2f"; + //psod_glyphs[0x05B2] = "hatafpatahhebrew"; + //psod_glyphs[0x05B2] = "hatafpatahnarrowhebrew"; + //psod_glyphs[0x05B2] = "hatafpatahquarterhebrew"; + //psod_glyphs[0x05B2] = "hatafpatahwidehebrew"; + psod_glyphs[0x05B3] = "hatafqamats"; + //psod_glyphs[0x05B3] = "hatafqamats1b"; + //psod_glyphs[0x05B3] = "hatafqamats28"; + //psod_glyphs[0x05B3] = "hatafqamats34"; + //psod_glyphs[0x05B3] = "hatafqamatshebrew"; + //psod_glyphs[0x05B3] = "hatafqamatsnarrowhebrew"; + //psod_glyphs[0x05B3] = "hatafqamatsquarterhebrew"; + //psod_glyphs[0x05B3] = "hatafqamatswidehebrew"; + psod_glyphs[0x05B1] = "hatafsegol"; + //psod_glyphs[0x05B1] = "hatafsegol17"; + //psod_glyphs[0x05B1] = "hatafsegol24"; + //psod_glyphs[0x05B1] = "hatafsegol30"; + //psod_glyphs[0x05B1] = "hatafsegolhebrew"; + //psod_glyphs[0x05B1] = "hatafsegolnarrowhebrew"; + //psod_glyphs[0x05B1] = "hatafsegolquarterhebrew"; + //psod_glyphs[0x05B1] = "hatafsegolwidehebrew"; + psod_glyphs[0x0127] = "hbar"; + psod_glyphs[0x310F] = "hbopomofo"; + psod_glyphs[0x1E2B] = "hbrevebelow"; + psod_glyphs[0x1E29] = "hcedilla"; + psod_glyphs[0x24D7] = "hcircle"; + psod_glyphs[0x0125] = "hcircumflex"; + psod_glyphs[0x1E27] = "hdieresis"; + psod_glyphs[0x1E23] = "hdotaccent"; + psod_glyphs[0x1E25] = "hdotbelow"; + psod_glyphs[0x05D4] = "he"; + psod_glyphs[0x2665] = "heart"; + psod_glyphs[0x2665] = "heartsuitblack"; + psod_glyphs[0x2661] = "heartsuitwhite"; + psod_glyphs[0xFB34] = "hedagesh"; + psod_glyphs[0xFB34] = "hedageshhebrew"; + psod_glyphs[0x06C1] = "hehaltonearabic"; + psod_glyphs[0x0647] = "heharabic"; + psod_glyphs[0x05D4] = "hehebrew"; + psod_glyphs[0xFBA7] = "hehfinalaltonearabic"; + psod_glyphs[0xFEEA] = "hehfinalalttwoarabic"; + psod_glyphs[0xFEEA] = "hehfinalarabic"; + psod_glyphs[0xFBA5] = "hehhamzaabovefinalarabic"; + psod_glyphs[0xFBA4] = "hehhamzaaboveisolatedarabic"; + psod_glyphs[0xFBA8] = "hehinitialaltonearabic"; + psod_glyphs[0xFEEB] = "hehinitialarabic"; + psod_glyphs[0x3078] = "hehiragana"; + psod_glyphs[0xFBA9] = "hehmedialaltonearabic"; + psod_glyphs[0xFEEC] = "hehmedialarabic"; + psod_glyphs[0x337B] = "heiseierasquare"; + psod_glyphs[0x30D8] = "hekatakana"; + psod_glyphs[0xFF8D] = "hekatakanahalfwidth"; + psod_glyphs[0x3336] = "hekutaarusquare"; + psod_glyphs[0x0267] = "henghook"; + psod_glyphs[0x3339] = "herutusquare"; + psod_glyphs[0x05D7] = "het"; + psod_glyphs[0x05D7] = "hethebrew"; + psod_glyphs[0x0266] = "hhook"; + psod_glyphs[0x02B1] = "hhooksuperior"; + psod_glyphs[0x327B] = "hieuhacirclekorean"; + psod_glyphs[0x321B] = "hieuhaparenkorean"; + psod_glyphs[0x326D] = "hieuhcirclekorean"; + psod_glyphs[0x314E] = "hieuhkorean"; + psod_glyphs[0x320D] = "hieuhparenkorean"; + psod_glyphs[0x3072] = "hihiragana"; + psod_glyphs[0x30D2] = "hikatakana"; + psod_glyphs[0xFF8B] = "hikatakanahalfwidth"; + psod_glyphs[0x05B4] = "hiriq"; + //psod_glyphs[0x05B4] = "hiriq14"; + //psod_glyphs[0x05B4] = "hiriq21"; + //psod_glyphs[0x05B4] = "hiriq2d"; + //psod_glyphs[0x05B4] = "hiriqhebrew"; + //psod_glyphs[0x05B4] = "hiriqnarrowhebrew"; + //psod_glyphs[0x05B4] = "hiriqquarterhebrew"; + //psod_glyphs[0x05B4] = "hiriqwidehebrew"; + psod_glyphs[0x1E96] = "hlinebelow"; + psod_glyphs[0xFF48] = "hmonospace"; + psod_glyphs[0x0570] = "hoarmenian"; + psod_glyphs[0x0E2B] = "hohipthai"; + psod_glyphs[0x307B] = "hohiragana"; + psod_glyphs[0x30DB] = "hokatakana"; + psod_glyphs[0xFF8E] = "hokatakanahalfwidth"; + psod_glyphs[0x05B9] = "holam"; + //psod_glyphs[0x05B9] = "holam19"; + //psod_glyphs[0x05B9] = "holam26"; + //psod_glyphs[0x05B9] = "holam32"; + //psod_glyphs[0x05B9] = "holamhebrew"; + //psod_glyphs[0x05B9] = "holamnarrowhebrew"; + //psod_glyphs[0x05B9] = "holamquarterhebrew"; + //psod_glyphs[0x05B9] = "holamwidehebrew"; + psod_glyphs[0x0E2E] = "honokhukthai"; + psod_glyphs[0x0309] = "hookabovecomb"; + psod_glyphs[0x0309] = "hookcmb"; + psod_glyphs[0x0321] = "hookpalatalizedbelowcmb"; + psod_glyphs[0x0322] = "hookretroflexbelowcmb"; + psod_glyphs[0x3342] = "hoonsquare"; + psod_glyphs[0x03E9] = "horicoptic"; + psod_glyphs[0x2015] = "horizontalbar"; + psod_glyphs[0x031B] = "horncmb"; + psod_glyphs[0x2668] = "hotsprings"; + psod_glyphs[0x2302] = "house"; + psod_glyphs[0x24A3] = "hparen"; + psod_glyphs[0x02B0] = "hsuperior"; + psod_glyphs[0x0265] = "hturned"; + psod_glyphs[0x3075] = "huhiragana"; + psod_glyphs[0x3333] = "huiitosquare"; + psod_glyphs[0x30D5] = "hukatakana"; + psod_glyphs[0xFF8C] = "hukatakanahalfwidth"; + psod_glyphs[0x02DD] = "hungarumlaut"; + psod_glyphs[0x030B] = "hungarumlautcmb"; + psod_glyphs[0x0195] = "hv"; + psod_glyphs[0x002D] = "hyphen"; + psod_glyphs[0xF6E5] = "hypheninferior"; + psod_glyphs[0xFF0D] = "hyphenmonospace"; + psod_glyphs[0xFE63] = "hyphensmall"; + psod_glyphs[0xF6E6] = "hyphensuperior"; + psod_glyphs[0x2010] = "hyphentwo"; + psod_glyphs[0x0069] = "i"; + psod_glyphs[0x00ED] = "iacute"; + psod_glyphs[0x044F] = "iacyrillic"; + psod_glyphs[0x0987] = "ibengali"; + psod_glyphs[0x3127] = "ibopomofo"; + psod_glyphs[0x012D] = "ibreve"; + psod_glyphs[0x01D0] = "icaron"; + psod_glyphs[0x24D8] = "icircle"; + psod_glyphs[0x00EE] = "icircumflex"; + psod_glyphs[0x0456] = "icyrillic"; + psod_glyphs[0x0209] = "idblgrave"; + psod_glyphs[0x328F] = "ideographearthcircle"; + psod_glyphs[0x328B] = "ideographfirecircle"; + psod_glyphs[0x323F] = "ideographicallianceparen"; + psod_glyphs[0x323A] = "ideographiccallparen"; + psod_glyphs[0x32A5] = "ideographiccentrecircle"; + psod_glyphs[0x3006] = "ideographicclose"; + psod_glyphs[0x3001] = "ideographiccomma"; + psod_glyphs[0xFF64] = "ideographiccommaleft"; + psod_glyphs[0x3237] = "ideographiccongratulationparen"; + psod_glyphs[0x32A3] = "ideographiccorrectcircle"; + psod_glyphs[0x322F] = "ideographicearthparen"; + psod_glyphs[0x323D] = "ideographicenterpriseparen"; + psod_glyphs[0x329D] = "ideographicexcellentcircle"; + psod_glyphs[0x3240] = "ideographicfestivalparen"; + psod_glyphs[0x3296] = "ideographicfinancialcircle"; + psod_glyphs[0x3236] = "ideographicfinancialparen"; + psod_glyphs[0x322B] = "ideographicfireparen"; + psod_glyphs[0x3232] = "ideographichaveparen"; + psod_glyphs[0x32A4] = "ideographichighcircle"; + psod_glyphs[0x3005] = "ideographiciterationmark"; + psod_glyphs[0x3298] = "ideographiclaborcircle"; + psod_glyphs[0x3238] = "ideographiclaborparen"; + psod_glyphs[0x32A7] = "ideographicleftcircle"; + psod_glyphs[0x32A6] = "ideographiclowcircle"; + psod_glyphs[0x32A9] = "ideographicmedicinecircle"; + psod_glyphs[0x322E] = "ideographicmetalparen"; + psod_glyphs[0x322A] = "ideographicmoonparen"; + psod_glyphs[0x3234] = "ideographicnameparen"; + psod_glyphs[0x3002] = "ideographicperiod"; + psod_glyphs[0x329E] = "ideographicprintcircle"; + psod_glyphs[0x3243] = "ideographicreachparen"; + psod_glyphs[0x3239] = "ideographicrepresentparen"; + psod_glyphs[0x323E] = "ideographicresourceparen"; + psod_glyphs[0x32A8] = "ideographicrightcircle"; + psod_glyphs[0x3299] = "ideographicsecretcircle"; + psod_glyphs[0x3242] = "ideographicselfparen"; + psod_glyphs[0x3233] = "ideographicsocietyparen"; + psod_glyphs[0x3000] = "ideographicspace"; + psod_glyphs[0x3235] = "ideographicspecialparen"; + psod_glyphs[0x3231] = "ideographicstockparen"; + psod_glyphs[0x323B] = "ideographicstudyparen"; + psod_glyphs[0x3230] = "ideographicsunparen"; + psod_glyphs[0x323C] = "ideographicsuperviseparen"; + psod_glyphs[0x322C] = "ideographicwaterparen"; + psod_glyphs[0x322D] = "ideographicwoodparen"; + psod_glyphs[0x3007] = "ideographiczero"; + psod_glyphs[0x328E] = "ideographmetalcircle"; + psod_glyphs[0x328A] = "ideographmooncircle"; + psod_glyphs[0x3294] = "ideographnamecircle"; + psod_glyphs[0x3290] = "ideographsuncircle"; + psod_glyphs[0x328C] = "ideographwatercircle"; + psod_glyphs[0x328D] = "ideographwoodcircle"; + psod_glyphs[0x0907] = "ideva"; + psod_glyphs[0x00EF] = "idieresis"; + psod_glyphs[0x1E2F] = "idieresisacute"; + psod_glyphs[0x04E5] = "idieresiscyrillic"; + psod_glyphs[0x1ECB] = "idotbelow"; + psod_glyphs[0x04D7] = "iebrevecyrillic"; + psod_glyphs[0x0435] = "iecyrillic"; + psod_glyphs[0x3275] = "ieungacirclekorean"; + psod_glyphs[0x3215] = "ieungaparenkorean"; + psod_glyphs[0x3267] = "ieungcirclekorean"; + psod_glyphs[0x3147] = "ieungkorean"; + psod_glyphs[0x3207] = "ieungparenkorean"; + psod_glyphs[0x00EC] = "igrave"; + psod_glyphs[0x0A87] = "igujarati"; + psod_glyphs[0x0A07] = "igurmukhi"; + psod_glyphs[0x3044] = "ihiragana"; + psod_glyphs[0x1EC9] = "ihookabove"; + psod_glyphs[0x0988] = "iibengali"; + psod_glyphs[0x0438] = "iicyrillic"; + psod_glyphs[0x0908] = "iideva"; + psod_glyphs[0x0A88] = "iigujarati"; + psod_glyphs[0x0A08] = "iigurmukhi"; + psod_glyphs[0x0A40] = "iimatragurmukhi"; + psod_glyphs[0x020B] = "iinvertedbreve"; + psod_glyphs[0x0439] = "iishortcyrillic"; + psod_glyphs[0x09C0] = "iivowelsignbengali"; + psod_glyphs[0x0940] = "iivowelsigndeva"; + psod_glyphs[0x0AC0] = "iivowelsigngujarati"; + psod_glyphs[0x0133] = "ij"; + psod_glyphs[0x30A4] = "ikatakana"; + psod_glyphs[0xFF72] = "ikatakanahalfwidth"; + psod_glyphs[0x3163] = "ikorean"; + psod_glyphs[0x02DC] = "ilde"; + psod_glyphs[0x05AC] = "iluyhebrew"; + psod_glyphs[0x012B] = "imacron"; + psod_glyphs[0x04E3] = "imacroncyrillic"; + psod_glyphs[0x2253] = "imageorapproximatelyequal"; + psod_glyphs[0x0A3F] = "imatragurmukhi"; + psod_glyphs[0xFF49] = "imonospace"; + psod_glyphs[0x2206] = "increment"; + psod_glyphs[0x221E] = "infinity"; + psod_glyphs[0x056B] = "iniarmenian"; + psod_glyphs[0x222B] = "integral"; + psod_glyphs[0x2321] = "integralbottom"; + psod_glyphs[0x2321] = "integralbt"; + psod_glyphs[0xF8F5] = "integralex"; + psod_glyphs[0x2320] = "integraltop"; + psod_glyphs[0x2320] = "integraltp"; + psod_glyphs[0x2229] = "intersection"; + psod_glyphs[0x3305] = "intisquare"; + psod_glyphs[0x25D8] = "invbullet"; + psod_glyphs[0x25D9] = "invcircle"; + psod_glyphs[0x263B] = "invsmileface"; + psod_glyphs[0x0451] = "iocyrillic"; + psod_glyphs[0x012F] = "iogonek"; + psod_glyphs[0x03B9] = "iota"; + psod_glyphs[0x03CA] = "iotadieresis"; + psod_glyphs[0x0390] = "iotadieresistonos"; + psod_glyphs[0x0269] = "iotalatin"; + psod_glyphs[0x03AF] = "iotatonos"; + psod_glyphs[0x24A4] = "iparen"; + psod_glyphs[0x0A72] = "irigurmukhi"; + psod_glyphs[0x3043] = "ismallhiragana"; + psod_glyphs[0x30A3] = "ismallkatakana"; + psod_glyphs[0xFF68] = "ismallkatakanahalfwidth"; + psod_glyphs[0x09FA] = "issharbengali"; + psod_glyphs[0x0268] = "istroke"; + psod_glyphs[0xF6ED] = "isuperior"; + psod_glyphs[0x309D] = "iterationhiragana"; + psod_glyphs[0x30FD] = "iterationkatakana"; + psod_glyphs[0x0129] = "itilde"; + psod_glyphs[0x1E2D] = "itildebelow"; + psod_glyphs[0x3129] = "iubopomofo"; + psod_glyphs[0x044E] = "iucyrillic"; + psod_glyphs[0x09BF] = "ivowelsignbengali"; + psod_glyphs[0x093F] = "ivowelsigndeva"; + psod_glyphs[0x0ABF] = "ivowelsigngujarati"; + psod_glyphs[0x0475] = "izhitsacyrillic"; + psod_glyphs[0x0477] = "izhitsadblgravecyrillic"; + psod_glyphs[0x006A] = "j"; + psod_glyphs[0x0571] = "jaarmenian"; + psod_glyphs[0x099C] = "jabengali"; + psod_glyphs[0x091C] = "jadeva"; + psod_glyphs[0x0A9C] = "jagujarati"; + psod_glyphs[0x0A1C] = "jagurmukhi"; + psod_glyphs[0x3110] = "jbopomofo"; + psod_glyphs[0x01F0] = "jcaron"; + psod_glyphs[0x24D9] = "jcircle"; + psod_glyphs[0x0135] = "jcircumflex"; + psod_glyphs[0x029D] = "jcrossedtail"; + psod_glyphs[0x025F] = "jdotlessstroke"; + psod_glyphs[0x0458] = "jecyrillic"; + psod_glyphs[0x062C] = "jeemarabic"; + psod_glyphs[0xFE9E] = "jeemfinalarabic"; + psod_glyphs[0xFE9F] = "jeeminitialarabic"; + psod_glyphs[0xFEA0] = "jeemmedialarabic"; + psod_glyphs[0x0698] = "jeharabic"; + psod_glyphs[0xFB8B] = "jehfinalarabic"; + psod_glyphs[0x099D] = "jhabengali"; + psod_glyphs[0x091D] = "jhadeva"; + psod_glyphs[0x0A9D] = "jhagujarati"; + psod_glyphs[0x0A1D] = "jhagurmukhi"; + psod_glyphs[0x057B] = "jheharmenian"; + psod_glyphs[0x3004] = "jis"; + psod_glyphs[0xFF4A] = "jmonospace"; + psod_glyphs[0x24A5] = "jparen"; + psod_glyphs[0x02B2] = "jsuperior"; + psod_glyphs[0x006B] = "k"; + psod_glyphs[0x04A1] = "kabashkircyrillic"; + psod_glyphs[0x0995] = "kabengali"; + psod_glyphs[0x1E31] = "kacute"; + psod_glyphs[0x043A] = "kacyrillic"; + psod_glyphs[0x049B] = "kadescendercyrillic"; + psod_glyphs[0x0915] = "kadeva"; + psod_glyphs[0x05DB] = "kaf"; + psod_glyphs[0x0643] = "kafarabic"; + psod_glyphs[0xFB3B] = "kafdagesh"; + psod_glyphs[0xFB3B] = "kafdageshhebrew"; + psod_glyphs[0xFEDA] = "kaffinalarabic"; + psod_glyphs[0x05DB] = "kafhebrew"; + psod_glyphs[0xFEDB] = "kafinitialarabic"; + psod_glyphs[0xFEDC] = "kafmedialarabic"; + psod_glyphs[0xFB4D] = "kafrafehebrew"; + psod_glyphs[0x0A95] = "kagujarati"; + psod_glyphs[0x0A15] = "kagurmukhi"; + psod_glyphs[0x304B] = "kahiragana"; + psod_glyphs[0x04C4] = "kahookcyrillic"; + psod_glyphs[0x30AB] = "kakatakana"; + psod_glyphs[0xFF76] = "kakatakanahalfwidth"; + psod_glyphs[0x03BA] = "kappa"; + psod_glyphs[0x03F0] = "kappasymbolgreek"; + psod_glyphs[0x3171] = "kapyeounmieumkorean"; + psod_glyphs[0x3184] = "kapyeounphieuphkorean"; + psod_glyphs[0x3178] = "kapyeounpieupkorean"; + psod_glyphs[0x3179] = "kapyeounssangpieupkorean"; + psod_glyphs[0x330D] = "karoriisquare"; + psod_glyphs[0x0640] = "kashidaautoarabic"; + psod_glyphs[0x0640] = "kashidaautonosidebearingarabic"; + psod_glyphs[0x30F5] = "kasmallkatakana"; + psod_glyphs[0x3384] = "kasquare"; + psod_glyphs[0x0650] = "kasraarabic"; + psod_glyphs[0x064D] = "kasratanarabic"; + psod_glyphs[0x049F] = "kastrokecyrillic"; + psod_glyphs[0xFF70] = "katahiraprolongmarkhalfwidth"; + psod_glyphs[0x049D] = "kaverticalstrokecyrillic"; + psod_glyphs[0x310E] = "kbopomofo"; + psod_glyphs[0x3389] = "kcalsquare"; + psod_glyphs[0x01E9] = "kcaron"; + psod_glyphs[0x0137] = "kcedilla"; + psod_glyphs[0x24DA] = "kcircle"; + psod_glyphs[0x0137] = "kcommaaccent"; + psod_glyphs[0x1E33] = "kdotbelow"; + psod_glyphs[0x0584] = "keharmenian"; + psod_glyphs[0x3051] = "kehiragana"; + psod_glyphs[0x30B1] = "kekatakana"; + psod_glyphs[0xFF79] = "kekatakanahalfwidth"; + psod_glyphs[0x056F] = "kenarmenian"; + psod_glyphs[0x30F6] = "kesmallkatakana"; + psod_glyphs[0x0138] = "kgreenlandic"; + psod_glyphs[0x0996] = "khabengali"; + psod_glyphs[0x0445] = "khacyrillic"; + psod_glyphs[0x0916] = "khadeva"; + psod_glyphs[0x0A96] = "khagujarati"; + psod_glyphs[0x0A16] = "khagurmukhi"; + psod_glyphs[0x062E] = "khaharabic"; + psod_glyphs[0xFEA6] = "khahfinalarabic"; + psod_glyphs[0xFEA7] = "khahinitialarabic"; + psod_glyphs[0xFEA8] = "khahmedialarabic"; + psod_glyphs[0x03E7] = "kheicoptic"; + psod_glyphs[0x0959] = "khhadeva"; + psod_glyphs[0x0A59] = "khhagurmukhi"; + psod_glyphs[0x3278] = "khieukhacirclekorean"; + psod_glyphs[0x3218] = "khieukhaparenkorean"; + psod_glyphs[0x326A] = "khieukhcirclekorean"; + psod_glyphs[0x314B] = "khieukhkorean"; + psod_glyphs[0x320A] = "khieukhparenkorean"; + psod_glyphs[0x0E02] = "khokhaithai"; + psod_glyphs[0x0E05] = "khokhonthai"; + psod_glyphs[0x0E03] = "khokhuatthai"; + psod_glyphs[0x0E04] = "khokhwaithai"; + psod_glyphs[0x0E5B] = "khomutthai"; + psod_glyphs[0x0199] = "khook"; + psod_glyphs[0x0E06] = "khorakhangthai"; + psod_glyphs[0x3391] = "khzsquare"; + psod_glyphs[0x304D] = "kihiragana"; + psod_glyphs[0x30AD] = "kikatakana"; + psod_glyphs[0xFF77] = "kikatakanahalfwidth"; + psod_glyphs[0x3315] = "kiroguramusquare"; + psod_glyphs[0x3316] = "kiromeetorusquare"; + psod_glyphs[0x3314] = "kirosquare"; + psod_glyphs[0x326E] = "kiyeokacirclekorean"; + psod_glyphs[0x320E] = "kiyeokaparenkorean"; + psod_glyphs[0x3260] = "kiyeokcirclekorean"; + psod_glyphs[0x3131] = "kiyeokkorean"; + psod_glyphs[0x3200] = "kiyeokparenkorean"; + psod_glyphs[0x3133] = "kiyeoksioskorean"; + psod_glyphs[0x045C] = "kjecyrillic"; + psod_glyphs[0x1E35] = "klinebelow"; + psod_glyphs[0x3398] = "klsquare"; + psod_glyphs[0x33A6] = "kmcubedsquare"; + psod_glyphs[0xFF4B] = "kmonospace"; + psod_glyphs[0x33A2] = "kmsquaredsquare"; + psod_glyphs[0x3053] = "kohiragana"; + psod_glyphs[0x33C0] = "kohmsquare"; + psod_glyphs[0x0E01] = "kokaithai"; + psod_glyphs[0x30B3] = "kokatakana"; + psod_glyphs[0xFF7A] = "kokatakanahalfwidth"; + psod_glyphs[0x331E] = "kooposquare"; + psod_glyphs[0x0481] = "koppacyrillic"; + psod_glyphs[0x327F] = "koreanstandardsymbol"; + psod_glyphs[0x0343] = "koroniscmb"; + psod_glyphs[0x24A6] = "kparen"; + psod_glyphs[0x33AA] = "kpasquare"; + psod_glyphs[0x046F] = "ksicyrillic"; + psod_glyphs[0x33CF] = "ktsquare"; + psod_glyphs[0x029E] = "kturned"; + psod_glyphs[0x304F] = "kuhiragana"; + psod_glyphs[0x30AF] = "kukatakana"; + psod_glyphs[0xFF78] = "kukatakanahalfwidth"; + psod_glyphs[0x33B8] = "kvsquare"; + psod_glyphs[0x33BE] = "kwsquare"; + psod_glyphs[0x006C] = "l"; + psod_glyphs[0x09B2] = "labengali"; + psod_glyphs[0x013A] = "lacute"; + psod_glyphs[0x0932] = "ladeva"; + psod_glyphs[0x0AB2] = "lagujarati"; + psod_glyphs[0x0A32] = "lagurmukhi"; + psod_glyphs[0x0E45] = "lakkhangyaothai"; + psod_glyphs[0xFEFC] = "lamaleffinalarabic"; + psod_glyphs[0xFEF8] = "lamalefhamzaabovefinalarabic"; + psod_glyphs[0xFEF7] = "lamalefhamzaaboveisolatedarabic"; + psod_glyphs[0xFEFA] = "lamalefhamzabelowfinalarabic"; + psod_glyphs[0xFEF9] = "lamalefhamzabelowisolatedarabic"; + psod_glyphs[0xFEFB] = "lamalefisolatedarabic"; + psod_glyphs[0xFEF6] = "lamalefmaddaabovefinalarabic"; + psod_glyphs[0xFEF5] = "lamalefmaddaaboveisolatedarabic"; + psod_glyphs[0x0644] = "lamarabic"; + psod_glyphs[0x03BB] = "lambda"; + psod_glyphs[0x019B] = "lambdastroke"; + psod_glyphs[0x05DC] = "lamed"; + psod_glyphs[0xFB3C] = "lameddagesh"; + psod_glyphs[0xFB3C] = "lameddageshhebrew"; + psod_glyphs[0x05DC] = "lamedhebrew"; + //psod_glyphs[0x05DC 05B9] = "lamedholam"; + //psod_glyphs[0x05DC 05B9 05BC] = "lamedholamdagesh"; + //psod_glyphs[0x05DC 05B9 05BC] = "lamedholamdageshhebrew"; + //psod_glyphs[0x05DC 05B9] = "lamedholamhebrew"; + psod_glyphs[0xFEDE] = "lamfinalarabic"; + psod_glyphs[0xFCCA] = "lamhahinitialarabic"; + psod_glyphs[0xFEDF] = "laminitialarabic"; + psod_glyphs[0xFCC9] = "lamjeeminitialarabic"; + psod_glyphs[0xFCCB] = "lamkhahinitialarabic"; + psod_glyphs[0xFDF2] = "lamlamhehisolatedarabic"; + psod_glyphs[0xFEE0] = "lammedialarabic"; + psod_glyphs[0xFD88] = "lammeemhahinitialarabic"; + psod_glyphs[0xFCCC] = "lammeeminitialarabic"; + //psod_glyphs[0xFEDF FEE4 FEA0] = "lammeemjeeminitialarabic"; + //psod_glyphs[0xFEDF FEE4 FEA8] = "lammeemkhahinitialarabic"; + psod_glyphs[0x25EF] = "largecircle"; + psod_glyphs[0x019A] = "lbar"; + psod_glyphs[0x026C] = "lbelt"; + psod_glyphs[0x310C] = "lbopomofo"; + psod_glyphs[0x013E] = "lcaron"; + psod_glyphs[0x013C] = "lcedilla"; + psod_glyphs[0x24DB] = "lcircle"; + psod_glyphs[0x1E3D] = "lcircumflexbelow"; + psod_glyphs[0x013C] = "lcommaaccent"; + psod_glyphs[0x0140] = "ldot"; + psod_glyphs[0x0140] = "ldotaccent"; + psod_glyphs[0x1E37] = "ldotbelow"; + psod_glyphs[0x1E39] = "ldotbelowmacron"; + psod_glyphs[0x031A] = "leftangleabovecmb"; + psod_glyphs[0x0318] = "lefttackbelowcmb"; + psod_glyphs[0x003C] = "less"; + psod_glyphs[0x2264] = "lessequal"; + psod_glyphs[0x22DA] = "lessequalorgreater"; + psod_glyphs[0xFF1C] = "lessmonospace"; + psod_glyphs[0x2272] = "lessorequivalent"; + psod_glyphs[0x2276] = "lessorgreater"; + psod_glyphs[0x2266] = "lessoverequal"; + psod_glyphs[0xFE64] = "lesssmall"; + psod_glyphs[0x026E] = "lezh"; + psod_glyphs[0x258C] = "lfblock"; + psod_glyphs[0x026D] = "lhookretroflex"; + psod_glyphs[0x20A4] = "lira"; + psod_glyphs[0x056C] = "liwnarmenian"; + psod_glyphs[0x01C9] = "lj"; + psod_glyphs[0x0459] = "ljecyrillic"; + psod_glyphs[0xF6C0] = "ll"; + psod_glyphs[0x0933] = "lladeva"; + psod_glyphs[0x0AB3] = "llagujarati"; + psod_glyphs[0x1E3B] = "llinebelow"; + psod_glyphs[0x0934] = "llladeva"; + psod_glyphs[0x09E1] = "llvocalicbengali"; + psod_glyphs[0x0961] = "llvocalicdeva"; + psod_glyphs[0x09E3] = "llvocalicvowelsignbengali"; + psod_glyphs[0x0963] = "llvocalicvowelsigndeva"; + psod_glyphs[0x026B] = "lmiddletilde"; + psod_glyphs[0xFF4C] = "lmonospace"; + psod_glyphs[0x33D0] = "lmsquare"; + psod_glyphs[0x0E2C] = "lochulathai"; + psod_glyphs[0x2227] = "logicaland"; + psod_glyphs[0x00AC] = "logicalnot"; + psod_glyphs[0x2310] = "logicalnotreversed"; + psod_glyphs[0x2228] = "logicalor"; + psod_glyphs[0x0E25] = "lolingthai"; + psod_glyphs[0x017F] = "longs"; + psod_glyphs[0xFE4E] = "lowlinecenterline"; + psod_glyphs[0x0332] = "lowlinecmb"; + psod_glyphs[0xFE4D] = "lowlinedashed"; + psod_glyphs[0x25CA] = "lozenge"; + psod_glyphs[0x24A7] = "lparen"; + psod_glyphs[0x0142] = "lslash"; + psod_glyphs[0x2113] = "lsquare"; + psod_glyphs[0xF6EE] = "lsuperior"; + psod_glyphs[0x2591] = "ltshade"; + psod_glyphs[0x0E26] = "luthai"; + psod_glyphs[0x098C] = "lvocalicbengali"; + psod_glyphs[0x090C] = "lvocalicdeva"; + psod_glyphs[0x09E2] = "lvocalicvowelsignbengali"; + psod_glyphs[0x0962] = "lvocalicvowelsigndeva"; + psod_glyphs[0x33D3] = "lxsquare"; + psod_glyphs[0x006D] = "m"; + psod_glyphs[0x09AE] = "mabengali"; + //psod_glyphs[0x00AF] = "macron"; + psod_glyphs[0x0331] = "macronbelowcmb"; + psod_glyphs[0x0304] = "macroncmb"; + psod_glyphs[0x02CD] = "macronlowmod"; + psod_glyphs[0xFFE3] = "macronmonospace"; + psod_glyphs[0x1E3F] = "macute"; + psod_glyphs[0x092E] = "madeva"; + psod_glyphs[0x0AAE] = "magujarati"; + psod_glyphs[0x0A2E] = "magurmukhi"; + psod_glyphs[0x05A4] = "mahapakhhebrew"; + psod_glyphs[0x05A4] = "mahapakhlefthebrew"; + psod_glyphs[0x307E] = "mahiragana"; + psod_glyphs[0xF895] = "maichattawalowleftthai"; + psod_glyphs[0xF894] = "maichattawalowrightthai"; + psod_glyphs[0x0E4B] = "maichattawathai"; + psod_glyphs[0xF893] = "maichattawaupperleftthai"; + psod_glyphs[0xF88C] = "maieklowleftthai"; + psod_glyphs[0xF88B] = "maieklowrightthai"; + psod_glyphs[0x0E48] = "maiekthai"; + psod_glyphs[0xF88A] = "maiekupperleftthai"; + psod_glyphs[0xF884] = "maihanakatleftthai"; + psod_glyphs[0x0E31] = "maihanakatthai"; + psod_glyphs[0xF889] = "maitaikhuleftthai"; + psod_glyphs[0x0E47] = "maitaikhuthai"; + psod_glyphs[0xF88F] = "maitholowleftthai"; + psod_glyphs[0xF88E] = "maitholowrightthai"; + psod_glyphs[0x0E49] = "maithothai"; + psod_glyphs[0xF88D] = "maithoupperleftthai"; + psod_glyphs[0xF892] = "maitrilowleftthai"; + psod_glyphs[0xF891] = "maitrilowrightthai"; + psod_glyphs[0x0E4A] = "maitrithai"; + psod_glyphs[0xF890] = "maitriupperleftthai"; + psod_glyphs[0x0E46] = "maiyamokthai"; + psod_glyphs[0x30DE] = "makatakana"; + psod_glyphs[0xFF8F] = "makatakanahalfwidth"; + psod_glyphs[0x2642] = "male"; + psod_glyphs[0x3347] = "mansyonsquare"; + psod_glyphs[0x05BE] = "maqafhebrew"; + psod_glyphs[0x2642] = "mars"; + psod_glyphs[0x05AF] = "masoracirclehebrew"; + psod_glyphs[0x3383] = "masquare"; + psod_glyphs[0x3107] = "mbopomofo"; + psod_glyphs[0x33D4] = "mbsquare"; + psod_glyphs[0x24DC] = "mcircle"; + psod_glyphs[0x33A5] = "mcubedsquare"; + psod_glyphs[0x1E41] = "mdotaccent"; + psod_glyphs[0x1E43] = "mdotbelow"; + psod_glyphs[0x0645] = "meemarabic"; + psod_glyphs[0xFEE2] = "meemfinalarabic"; + psod_glyphs[0xFEE3] = "meeminitialarabic"; + psod_glyphs[0xFEE4] = "meemmedialarabic"; + psod_glyphs[0xFCD1] = "meemmeeminitialarabic"; + psod_glyphs[0xFC48] = "meemmeemisolatedarabic"; + psod_glyphs[0x334D] = "meetorusquare"; + psod_glyphs[0x3081] = "mehiragana"; + psod_glyphs[0x337E] = "meizierasquare"; + psod_glyphs[0x30E1] = "mekatakana"; + psod_glyphs[0xFF92] = "mekatakanahalfwidth"; + psod_glyphs[0x05DE] = "mem"; + psod_glyphs[0xFB3E] = "memdagesh"; + psod_glyphs[0xFB3E] = "memdageshhebrew"; + psod_glyphs[0x05DE] = "memhebrew"; + psod_glyphs[0x0574] = "menarmenian"; + psod_glyphs[0x05A5] = "merkhahebrew"; + psod_glyphs[0x05A6] = "merkhakefulahebrew"; + psod_glyphs[0x05A6] = "merkhakefulalefthebrew"; + psod_glyphs[0x05A5] = "merkhalefthebrew"; + psod_glyphs[0x0271] = "mhook"; + psod_glyphs[0x3392] = "mhzsquare"; + psod_glyphs[0xFF65] = "middledotkatakanahalfwidth"; + //psod_glyphs[0x00B7] = "middot"; + psod_glyphs[0x3272] = "mieumacirclekorean"; + psod_glyphs[0x3212] = "mieumaparenkorean"; + psod_glyphs[0x3264] = "mieumcirclekorean"; + psod_glyphs[0x3141] = "mieumkorean"; + psod_glyphs[0x3170] = "mieumpansioskorean"; + psod_glyphs[0x3204] = "mieumparenkorean"; + psod_glyphs[0x316E] = "mieumpieupkorean"; + psod_glyphs[0x316F] = "mieumsioskorean"; + psod_glyphs[0x307F] = "mihiragana"; + psod_glyphs[0x30DF] = "mikatakana"; + psod_glyphs[0xFF90] = "mikatakanahalfwidth"; + psod_glyphs[0x2212] = "minus"; + psod_glyphs[0x0320] = "minusbelowcmb"; + psod_glyphs[0x2296] = "minuscircle"; + psod_glyphs[0x02D7] = "minusmod"; + psod_glyphs[0x2213] = "minusplus"; + psod_glyphs[0x2032] = "minute"; + psod_glyphs[0x334A] = "miribaarusquare"; + psod_glyphs[0x3349] = "mirisquare"; + psod_glyphs[0x0270] = "mlonglegturned"; + psod_glyphs[0x3396] = "mlsquare"; + psod_glyphs[0x33A3] = "mmcubedsquare"; + psod_glyphs[0xFF4D] = "mmonospace"; + psod_glyphs[0x339F] = "mmsquaredsquare"; + psod_glyphs[0x3082] = "mohiragana"; + psod_glyphs[0x33C1] = "mohmsquare"; + psod_glyphs[0x30E2] = "mokatakana"; + psod_glyphs[0xFF93] = "mokatakanahalfwidth"; + psod_glyphs[0x33D6] = "molsquare"; + psod_glyphs[0x0E21] = "momathai"; + psod_glyphs[0x33A7] = "moverssquare"; + psod_glyphs[0x33A8] = "moverssquaredsquare"; + psod_glyphs[0x24A8] = "mparen"; + psod_glyphs[0x33AB] = "mpasquare"; + psod_glyphs[0x33B3] = "mssquare"; + psod_glyphs[0xF6EF] = "msuperior"; + psod_glyphs[0x026F] = "mturned"; + psod_glyphs[0x00B5] = "mu"; + //psod_glyphs[0x00B5] = "mu1"; + psod_glyphs[0x3382] = "muasquare"; + psod_glyphs[0x226B] = "muchgreater"; + psod_glyphs[0x226A] = "muchless"; + psod_glyphs[0x338C] = "mufsquare"; + psod_glyphs[0x03BC] = "mugreek"; + psod_glyphs[0x338D] = "mugsquare"; + psod_glyphs[0x3080] = "muhiragana"; + psod_glyphs[0x30E0] = "mukatakana"; + psod_glyphs[0xFF91] = "mukatakanahalfwidth"; + psod_glyphs[0x3395] = "mulsquare"; + psod_glyphs[0x00D7] = "multiply"; + psod_glyphs[0x339B] = "mumsquare"; + psod_glyphs[0x05A3] = "munahhebrew"; + psod_glyphs[0x05A3] = "munahlefthebrew"; + psod_glyphs[0x266A] = "musicalnote"; + psod_glyphs[0x266B] = "musicalnotedbl"; + psod_glyphs[0x266D] = "musicflatsign"; + psod_glyphs[0x266F] = "musicsharpsign"; + psod_glyphs[0x33B2] = "mussquare"; + psod_glyphs[0x33B6] = "muvsquare"; + psod_glyphs[0x33BC] = "muwsquare"; + psod_glyphs[0x33B9] = "mvmegasquare"; + psod_glyphs[0x33B7] = "mvsquare"; + psod_glyphs[0x33BF] = "mwmegasquare"; + psod_glyphs[0x33BD] = "mwsquare"; + psod_glyphs[0x006E] = "n"; + psod_glyphs[0x09A8] = "nabengali"; + psod_glyphs[0x2207] = "nabla"; + psod_glyphs[0x0144] = "nacute"; + psod_glyphs[0x0928] = "nadeva"; + psod_glyphs[0x0AA8] = "nagujarati"; + psod_glyphs[0x0A28] = "nagurmukhi"; + psod_glyphs[0x306A] = "nahiragana"; + psod_glyphs[0x30CA] = "nakatakana"; + psod_glyphs[0xFF85] = "nakatakanahalfwidth"; + psod_glyphs[0x0149] = "napostrophe"; + psod_glyphs[0x3381] = "nasquare"; + psod_glyphs[0x310B] = "nbopomofo"; + //psod_glyphs[0x00A0] = "nbspace"; + psod_glyphs[0x0148] = "ncaron"; + psod_glyphs[0x0146] = "ncedilla"; + psod_glyphs[0x24DD] = "ncircle"; + psod_glyphs[0x1E4B] = "ncircumflexbelow"; + psod_glyphs[0x0146] = "ncommaaccent"; + psod_glyphs[0x1E45] = "ndotaccent"; + psod_glyphs[0x1E47] = "ndotbelow"; + psod_glyphs[0x306D] = "nehiragana"; + psod_glyphs[0x30CD] = "nekatakana"; + psod_glyphs[0xFF88] = "nekatakanahalfwidth"; + psod_glyphs[0x20AA] = "newsheqelsign"; + psod_glyphs[0x338B] = "nfsquare"; + psod_glyphs[0x0999] = "ngabengali"; + psod_glyphs[0x0919] = "ngadeva"; + psod_glyphs[0x0A99] = "ngagujarati"; + psod_glyphs[0x0A19] = "ngagurmukhi"; + psod_glyphs[0x0E07] = "ngonguthai"; + psod_glyphs[0x3093] = "nhiragana"; + psod_glyphs[0x0272] = "nhookleft"; + psod_glyphs[0x0273] = "nhookretroflex"; + psod_glyphs[0x326F] = "nieunacirclekorean"; + psod_glyphs[0x320F] = "nieunaparenkorean"; + psod_glyphs[0x3135] = "nieuncieuckorean"; + psod_glyphs[0x3261] = "nieuncirclekorean"; + psod_glyphs[0x3136] = "nieunhieuhkorean"; + psod_glyphs[0x3134] = "nieunkorean"; + psod_glyphs[0x3168] = "nieunpansioskorean"; + psod_glyphs[0x3201] = "nieunparenkorean"; + psod_glyphs[0x3167] = "nieunsioskorean"; + psod_glyphs[0x3166] = "nieuntikeutkorean"; + psod_glyphs[0x306B] = "nihiragana"; + psod_glyphs[0x30CB] = "nikatakana"; + psod_glyphs[0xFF86] = "nikatakanahalfwidth"; + psod_glyphs[0xF899] = "nikhahitleftthai"; + psod_glyphs[0x0E4D] = "nikhahitthai"; + psod_glyphs[0x0039] = "nine"; + psod_glyphs[0x0669] = "ninearabic"; + psod_glyphs[0x09EF] = "ninebengali"; + psod_glyphs[0x2468] = "ninecircle"; + psod_glyphs[0x2792] = "ninecircleinversesansserif"; + psod_glyphs[0x096F] = "ninedeva"; + psod_glyphs[0x0AEF] = "ninegujarati"; + psod_glyphs[0x0A6F] = "ninegurmukhi"; + psod_glyphs[0x0669] = "ninehackarabic"; + psod_glyphs[0x3029] = "ninehangzhou"; + psod_glyphs[0x3228] = "nineideographicparen"; + psod_glyphs[0x2089] = "nineinferior"; + psod_glyphs[0xFF19] = "ninemonospace"; + psod_glyphs[0xF739] = "nineoldstyle"; + psod_glyphs[0x247C] = "nineparen"; + psod_glyphs[0x2490] = "nineperiod"; + psod_glyphs[0x06F9] = "ninepersian"; + psod_glyphs[0x2178] = "nineroman"; + psod_glyphs[0x2079] = "ninesuperior"; + psod_glyphs[0x2472] = "nineteencircle"; + psod_glyphs[0x2486] = "nineteenparen"; + psod_glyphs[0x249A] = "nineteenperiod"; + psod_glyphs[0x0E59] = "ninethai"; + psod_glyphs[0x01CC] = "nj"; + psod_glyphs[0x045A] = "njecyrillic"; + psod_glyphs[0x30F3] = "nkatakana"; + psod_glyphs[0xFF9D] = "nkatakanahalfwidth"; + psod_glyphs[0x019E] = "nlegrightlong"; + psod_glyphs[0x1E49] = "nlinebelow"; + psod_glyphs[0xFF4E] = "nmonospace"; + psod_glyphs[0x339A] = "nmsquare"; + psod_glyphs[0x09A3] = "nnabengali"; + psod_glyphs[0x0923] = "nnadeva"; + psod_glyphs[0x0AA3] = "nnagujarati"; + psod_glyphs[0x0A23] = "nnagurmukhi"; + psod_glyphs[0x0929] = "nnnadeva"; + psod_glyphs[0x306E] = "nohiragana"; + psod_glyphs[0x30CE] = "nokatakana"; + psod_glyphs[0xFF89] = "nokatakanahalfwidth"; + psod_glyphs[0x00A0] = "nonbreakingspace"; + psod_glyphs[0x0E13] = "nonenthai"; + psod_glyphs[0x0E19] = "nonuthai"; + psod_glyphs[0x0646] = "noonarabic"; + psod_glyphs[0xFEE6] = "noonfinalarabic"; + psod_glyphs[0x06BA] = "noonghunnaarabic"; + psod_glyphs[0xFB9F] = "noonghunnafinalarabic"; + //psod_glyphs[0xFEE7 FEEC] = "noonhehinitialarabic"; + psod_glyphs[0xFEE7] = "nooninitialarabic"; + psod_glyphs[0xFCD2] = "noonjeeminitialarabic"; + psod_glyphs[0xFC4B] = "noonjeemisolatedarabic"; + psod_glyphs[0xFEE8] = "noonmedialarabic"; + psod_glyphs[0xFCD5] = "noonmeeminitialarabic"; + psod_glyphs[0xFC4E] = "noonmeemisolatedarabic"; + psod_glyphs[0xFC8D] = "noonnoonfinalarabic"; + psod_glyphs[0x220C] = "notcontains"; + psod_glyphs[0x2209] = "notelement"; + psod_glyphs[0x2209] = "notelementof"; + psod_glyphs[0x2260] = "notequal"; + psod_glyphs[0x226F] = "notgreater"; + psod_glyphs[0x2271] = "notgreaternorequal"; + psod_glyphs[0x2279] = "notgreaternorless"; + psod_glyphs[0x2262] = "notidentical"; + psod_glyphs[0x226E] = "notless"; + psod_glyphs[0x2270] = "notlessnorequal"; + psod_glyphs[0x2226] = "notparallel"; + psod_glyphs[0x2280] = "notprecedes"; + psod_glyphs[0x2284] = "notsubset"; + psod_glyphs[0x2281] = "notsucceeds"; + psod_glyphs[0x2285] = "notsuperset"; + psod_glyphs[0x0576] = "nowarmenian"; + psod_glyphs[0x24A9] = "nparen"; + psod_glyphs[0x33B1] = "nssquare"; + psod_glyphs[0x207F] = "nsuperior"; + psod_glyphs[0x00F1] = "ntilde"; + psod_glyphs[0x03BD] = "nu"; + psod_glyphs[0x306C] = "nuhiragana"; + psod_glyphs[0x30CC] = "nukatakana"; + psod_glyphs[0xFF87] = "nukatakanahalfwidth"; + psod_glyphs[0x09BC] = "nuktabengali"; + psod_glyphs[0x093C] = "nuktadeva"; + psod_glyphs[0x0ABC] = "nuktagujarati"; + psod_glyphs[0x0A3C] = "nuktagurmukhi"; + psod_glyphs[0x0023] = "numbersign"; + psod_glyphs[0xFF03] = "numbersignmonospace"; + psod_glyphs[0xFE5F] = "numbersignsmall"; + psod_glyphs[0x0374] = "numeralsigngreek"; + psod_glyphs[0x0375] = "numeralsignlowergreek"; + psod_glyphs[0x2116] = "numero"; + psod_glyphs[0x05E0] = "nun"; + psod_glyphs[0xFB40] = "nundagesh"; + psod_glyphs[0xFB40] = "nundageshhebrew"; + psod_glyphs[0x05E0] = "nunhebrew"; + psod_glyphs[0x33B5] = "nvsquare"; + psod_glyphs[0x33BB] = "nwsquare"; + psod_glyphs[0x099E] = "nyabengali"; + psod_glyphs[0x091E] = "nyadeva"; + psod_glyphs[0x0A9E] = "nyagujarati"; + psod_glyphs[0x0A1E] = "nyagurmukhi"; + psod_glyphs[0x006F] = "o"; + psod_glyphs[0x00F3] = "oacute"; + psod_glyphs[0x0E2D] = "oangthai"; + psod_glyphs[0x0275] = "obarred"; + psod_glyphs[0x04E9] = "obarredcyrillic"; + psod_glyphs[0x04EB] = "obarreddieresiscyrillic"; + psod_glyphs[0x0993] = "obengali"; + psod_glyphs[0x311B] = "obopomofo"; + psod_glyphs[0x014F] = "obreve"; + psod_glyphs[0x0911] = "ocandradeva"; + psod_glyphs[0x0A91] = "ocandragujarati"; + psod_glyphs[0x0949] = "ocandravowelsigndeva"; + psod_glyphs[0x0AC9] = "ocandravowelsigngujarati"; + psod_glyphs[0x01D2] = "ocaron"; + psod_glyphs[0x24DE] = "ocircle"; + psod_glyphs[0x00F4] = "ocircumflex"; + psod_glyphs[0x1ED1] = "ocircumflexacute"; + psod_glyphs[0x1ED9] = "ocircumflexdotbelow"; + psod_glyphs[0x1ED3] = "ocircumflexgrave"; + psod_glyphs[0x1ED5] = "ocircumflexhookabove"; + psod_glyphs[0x1ED7] = "ocircumflextilde"; + psod_glyphs[0x043E] = "ocyrillic"; + psod_glyphs[0x0151] = "odblacute"; + psod_glyphs[0x020D] = "odblgrave"; + psod_glyphs[0x0913] = "odeva"; + psod_glyphs[0x00F6] = "odieresis"; + psod_glyphs[0x04E7] = "odieresiscyrillic"; + psod_glyphs[0x1ECD] = "odotbelow"; + psod_glyphs[0x0153] = "oe"; + psod_glyphs[0x315A] = "oekorean"; + psod_glyphs[0x02DB] = "ogonek"; + psod_glyphs[0x0328] = "ogonekcmb"; + psod_glyphs[0x00F2] = "ograve"; + psod_glyphs[0x0A93] = "ogujarati"; + psod_glyphs[0x0585] = "oharmenian"; + psod_glyphs[0x304A] = "ohiragana"; + psod_glyphs[0x1ECF] = "ohookabove"; + psod_glyphs[0x01A1] = "ohorn"; + psod_glyphs[0x1EDB] = "ohornacute"; + psod_glyphs[0x1EE3] = "ohorndotbelow"; + psod_glyphs[0x1EDD] = "ohorngrave"; + psod_glyphs[0x1EDF] = "ohornhookabove"; + psod_glyphs[0x1EE1] = "ohorntilde"; + psod_glyphs[0x0151] = "ohungarumlaut"; + psod_glyphs[0x01A3] = "oi"; + psod_glyphs[0x020F] = "oinvertedbreve"; + psod_glyphs[0x30AA] = "okatakana"; + psod_glyphs[0xFF75] = "okatakanahalfwidth"; + psod_glyphs[0x3157] = "okorean"; + psod_glyphs[0x05AB] = "olehebrew"; + psod_glyphs[0x014D] = "omacron"; + psod_glyphs[0x1E53] = "omacronacute"; + psod_glyphs[0x1E51] = "omacrongrave"; + psod_glyphs[0x0950] = "omdeva"; + psod_glyphs[0x03C9] = "omega"; + psod_glyphs[0x03D6] = "omega1"; + psod_glyphs[0x0461] = "omegacyrillic"; + psod_glyphs[0x0277] = "omegalatinclosed"; + psod_glyphs[0x047B] = "omegaroundcyrillic"; + psod_glyphs[0x047D] = "omegatitlocyrillic"; + psod_glyphs[0x03CE] = "omegatonos"; + psod_glyphs[0x0AD0] = "omgujarati"; + psod_glyphs[0x03BF] = "omicron"; + psod_glyphs[0x03CC] = "omicrontonos"; + psod_glyphs[0xFF4F] = "omonospace"; + psod_glyphs[0x0031] = "one"; + psod_glyphs[0x0661] = "onearabic"; + psod_glyphs[0x09E7] = "onebengali"; + psod_glyphs[0x2460] = "onecircle"; + psod_glyphs[0x278A] = "onecircleinversesansserif"; + psod_glyphs[0x0967] = "onedeva"; + psod_glyphs[0x2024] = "onedotenleader"; + psod_glyphs[0x215B] = "oneeighth"; + psod_glyphs[0xF6DC] = "onefitted"; + psod_glyphs[0x0AE7] = "onegujarati"; + psod_glyphs[0x0A67] = "onegurmukhi"; + psod_glyphs[0x0661] = "onehackarabic"; + psod_glyphs[0x00BD] = "onehalf"; + psod_glyphs[0x3021] = "onehangzhou"; + psod_glyphs[0x3220] = "oneideographicparen"; + psod_glyphs[0x2081] = "oneinferior"; + psod_glyphs[0xFF11] = "onemonospace"; + psod_glyphs[0x09F4] = "onenumeratorbengali"; + psod_glyphs[0xF731] = "oneoldstyle"; + psod_glyphs[0x2474] = "oneparen"; + psod_glyphs[0x2488] = "oneperiod"; + psod_glyphs[0x06F1] = "onepersian"; + psod_glyphs[0x00BC] = "onequarter"; + psod_glyphs[0x2170] = "oneroman"; + psod_glyphs[0x00B9] = "onesuperior"; + psod_glyphs[0x0E51] = "onethai"; + psod_glyphs[0x2153] = "onethird"; + psod_glyphs[0x01EB] = "oogonek"; + psod_glyphs[0x01ED] = "oogonekmacron"; + psod_glyphs[0x0A13] = "oogurmukhi"; + psod_glyphs[0x0A4B] = "oomatragurmukhi"; + psod_glyphs[0x0254] = "oopen"; + psod_glyphs[0x24AA] = "oparen"; + psod_glyphs[0x25E6] = "openbullet"; + psod_glyphs[0x2325] = "option"; + psod_glyphs[0x00AA] = "ordfeminine"; + psod_glyphs[0x00BA] = "ordmasculine"; + psod_glyphs[0x221F] = "orthogonal"; + psod_glyphs[0x0912] = "oshortdeva"; + psod_glyphs[0x094A] = "oshortvowelsigndeva"; + psod_glyphs[0x00F8] = "oslash"; + psod_glyphs[0x01FF] = "oslashacute"; + psod_glyphs[0x3049] = "osmallhiragana"; + psod_glyphs[0x30A9] = "osmallkatakana"; + psod_glyphs[0xFF6B] = "osmallkatakanahalfwidth"; + psod_glyphs[0x01FF] = "ostrokeacute"; + psod_glyphs[0xF6F0] = "osuperior"; + psod_glyphs[0x047F] = "otcyrillic"; + psod_glyphs[0x00F5] = "otilde"; + psod_glyphs[0x1E4D] = "otildeacute"; + psod_glyphs[0x1E4F] = "otildedieresis"; + psod_glyphs[0x3121] = "oubopomofo"; + psod_glyphs[0x203E] = "overline"; + psod_glyphs[0xFE4A] = "overlinecenterline"; + psod_glyphs[0x0305] = "overlinecmb"; + psod_glyphs[0xFE49] = "overlinedashed"; + psod_glyphs[0xFE4C] = "overlinedblwavy"; + psod_glyphs[0xFE4B] = "overlinewavy"; + psod_glyphs[0x00AF] = "overscore"; + psod_glyphs[0x09CB] = "ovowelsignbengali"; + psod_glyphs[0x094B] = "ovowelsigndeva"; + psod_glyphs[0x0ACB] = "ovowelsigngujarati"; + psod_glyphs[0x0070] = "p"; + psod_glyphs[0x3380] = "paampssquare"; + psod_glyphs[0x332B] = "paasentosquare"; + psod_glyphs[0x09AA] = "pabengali"; + psod_glyphs[0x1E55] = "pacute"; + psod_glyphs[0x092A] = "padeva"; + psod_glyphs[0x21DF] = "pagedown"; + psod_glyphs[0x21DE] = "pageup"; + psod_glyphs[0x0AAA] = "pagujarati"; + psod_glyphs[0x0A2A] = "pagurmukhi"; + psod_glyphs[0x3071] = "pahiragana"; + psod_glyphs[0x0E2F] = "paiyannoithai"; + psod_glyphs[0x30D1] = "pakatakana"; + psod_glyphs[0x0484] = "palatalizationcyrilliccmb"; + psod_glyphs[0x04C0] = "palochkacyrillic"; + psod_glyphs[0x317F] = "pansioskorean"; + psod_glyphs[0x00B6] = "paragraph"; + psod_glyphs[0x2225] = "parallel"; + psod_glyphs[0x0028] = "parenleft"; + psod_glyphs[0xFD3E] = "parenleftaltonearabic"; + psod_glyphs[0xF8ED] = "parenleftbt"; + psod_glyphs[0xF8EC] = "parenleftex"; + psod_glyphs[0x208D] = "parenleftinferior"; + psod_glyphs[0xFF08] = "parenleftmonospace"; + psod_glyphs[0xFE59] = "parenleftsmall"; + psod_glyphs[0x207D] = "parenleftsuperior"; + psod_glyphs[0xF8EB] = "parenlefttp"; + psod_glyphs[0xFE35] = "parenleftvertical"; + psod_glyphs[0x0029] = "parenright"; + psod_glyphs[0xFD3F] = "parenrightaltonearabic"; + psod_glyphs[0xF8F8] = "parenrightbt"; + psod_glyphs[0xF8F7] = "parenrightex"; + psod_glyphs[0x208E] = "parenrightinferior"; + psod_glyphs[0xFF09] = "parenrightmonospace"; + psod_glyphs[0xFE5A] = "parenrightsmall"; + psod_glyphs[0x207E] = "parenrightsuperior"; + psod_glyphs[0xF8F6] = "parenrighttp"; + psod_glyphs[0xFE36] = "parenrightvertical"; + psod_glyphs[0x2202] = "partialdiff"; + psod_glyphs[0x05C0] = "paseqhebrew"; + psod_glyphs[0x0599] = "pashtahebrew"; + psod_glyphs[0x33A9] = "pasquare"; + psod_glyphs[0x05B7] = "patah"; + //psod_glyphs[0x05B7] = "patah11"; + //psod_glyphs[0x05B7] = "patah1d"; + //psod_glyphs[0x05B7] = "patah2a"; + //psod_glyphs[0x05B7] = "patahhebrew"; + //psod_glyphs[0x05B7] = "patahnarrowhebrew"; + //psod_glyphs[0x05B7] = "patahquarterhebrew"; + //psod_glyphs[0x05B7] = "patahwidehebrew"; + psod_glyphs[0x05A1] = "pazerhebrew"; + psod_glyphs[0x3106] = "pbopomofo"; + psod_glyphs[0x24DF] = "pcircle"; + psod_glyphs[0x1E57] = "pdotaccent"; + psod_glyphs[0x05E4] = "pe"; + psod_glyphs[0x043F] = "pecyrillic"; + psod_glyphs[0xFB44] = "pedagesh"; + psod_glyphs[0xFB44] = "pedageshhebrew"; + psod_glyphs[0x333B] = "peezisquare"; + psod_glyphs[0xFB43] = "pefinaldageshhebrew"; + psod_glyphs[0x067E] = "peharabic"; + psod_glyphs[0x057A] = "peharmenian"; + psod_glyphs[0x05E4] = "pehebrew"; + psod_glyphs[0xFB57] = "pehfinalarabic"; + psod_glyphs[0xFB58] = "pehinitialarabic"; + psod_glyphs[0x307A] = "pehiragana"; + psod_glyphs[0xFB59] = "pehmedialarabic"; + psod_glyphs[0x30DA] = "pekatakana"; + psod_glyphs[0x04A7] = "pemiddlehookcyrillic"; + psod_glyphs[0xFB4E] = "perafehebrew"; + psod_glyphs[0x0025] = "percent"; + psod_glyphs[0x066A] = "percentarabic"; + psod_glyphs[0xFF05] = "percentmonospace"; + psod_glyphs[0xFE6A] = "percentsmall"; + psod_glyphs[0x002E] = "period"; + psod_glyphs[0x0589] = "periodarmenian"; + psod_glyphs[0x00B7] = "periodcentered"; + psod_glyphs[0xFF61] = "periodhalfwidth"; + psod_glyphs[0xF6E7] = "periodinferior"; + psod_glyphs[0xFF0E] = "periodmonospace"; + psod_glyphs[0xFE52] = "periodsmall"; + psod_glyphs[0xF6E8] = "periodsuperior"; + psod_glyphs[0x0342] = "perispomenigreekcmb"; + psod_glyphs[0x22A5] = "perpendicular"; + psod_glyphs[0x2030] = "perthousand"; + psod_glyphs[0x20A7] = "peseta"; + psod_glyphs[0x338A] = "pfsquare"; + psod_glyphs[0x09AB] = "phabengali"; + psod_glyphs[0x092B] = "phadeva"; + psod_glyphs[0x0AAB] = "phagujarati"; + psod_glyphs[0x0A2B] = "phagurmukhi"; + psod_glyphs[0x03C6] = "phi"; + psod_glyphs[0x03D5] = "phi1"; + psod_glyphs[0x327A] = "phieuphacirclekorean"; + psod_glyphs[0x321A] = "phieuphaparenkorean"; + psod_glyphs[0x326C] = "phieuphcirclekorean"; + psod_glyphs[0x314D] = "phieuphkorean"; + psod_glyphs[0x320C] = "phieuphparenkorean"; + psod_glyphs[0x0278] = "philatin"; + psod_glyphs[0x0E3A] = "phinthuthai"; + psod_glyphs[0x03D5] = "phisymbolgreek"; + psod_glyphs[0x01A5] = "phook"; + psod_glyphs[0x0E1E] = "phophanthai"; + psod_glyphs[0x0E1C] = "phophungthai"; + psod_glyphs[0x0E20] = "phosamphaothai"; + psod_glyphs[0x03C0] = "pi"; + psod_glyphs[0x3273] = "pieupacirclekorean"; + psod_glyphs[0x3213] = "pieupaparenkorean"; + psod_glyphs[0x3176] = "pieupcieuckorean"; + psod_glyphs[0x3265] = "pieupcirclekorean"; + psod_glyphs[0x3172] = "pieupkiyeokkorean"; + psod_glyphs[0x3142] = "pieupkorean"; + psod_glyphs[0x3205] = "pieupparenkorean"; + psod_glyphs[0x3174] = "pieupsioskiyeokkorean"; + psod_glyphs[0x3144] = "pieupsioskorean"; + psod_glyphs[0x3175] = "pieupsiostikeutkorean"; + psod_glyphs[0x3177] = "pieupthieuthkorean"; + psod_glyphs[0x3173] = "pieuptikeutkorean"; + psod_glyphs[0x3074] = "pihiragana"; + psod_glyphs[0x30D4] = "pikatakana"; + psod_glyphs[0x03D6] = "pisymbolgreek"; + psod_glyphs[0x0583] = "piwrarmenian"; + psod_glyphs[0x002B] = "plus"; + psod_glyphs[0x031F] = "plusbelowcmb"; + psod_glyphs[0x2295] = "pluscircle"; + psod_glyphs[0x00B1] = "plusminus"; + psod_glyphs[0x02D6] = "plusmod"; + psod_glyphs[0xFF0B] = "plusmonospace"; + psod_glyphs[0xFE62] = "plussmall"; + psod_glyphs[0x207A] = "plussuperior"; + psod_glyphs[0xFF50] = "pmonospace"; + psod_glyphs[0x33D8] = "pmsquare"; + psod_glyphs[0x307D] = "pohiragana"; + psod_glyphs[0x261F] = "pointingindexdownwhite"; + psod_glyphs[0x261C] = "pointingindexleftwhite"; + psod_glyphs[0x261E] = "pointingindexrightwhite"; + psod_glyphs[0x261D] = "pointingindexupwhite"; + psod_glyphs[0x30DD] = "pokatakana"; + psod_glyphs[0x0E1B] = "poplathai"; + psod_glyphs[0x3012] = "postalmark"; + psod_glyphs[0x3020] = "postalmarkface"; + psod_glyphs[0x24AB] = "pparen"; + psod_glyphs[0x227A] = "precedes"; + psod_glyphs[0x211E] = "prescription"; + psod_glyphs[0x02B9] = "primemod"; + psod_glyphs[0x2035] = "primereversed"; + psod_glyphs[0x220F] = "product"; + psod_glyphs[0x2305] = "projective"; + psod_glyphs[0x30FC] = "prolongedkana"; + psod_glyphs[0x2318] = "propellor"; + psod_glyphs[0x2282] = "propersubset"; + psod_glyphs[0x2283] = "propersuperset"; + psod_glyphs[0x2237] = "proportion"; + psod_glyphs[0x221D] = "proportional"; + psod_glyphs[0x03C8] = "psi"; + psod_glyphs[0x0471] = "psicyrillic"; + psod_glyphs[0x0486] = "psilipneumatacyrilliccmb"; + psod_glyphs[0x33B0] = "pssquare"; + psod_glyphs[0x3077] = "puhiragana"; + psod_glyphs[0x30D7] = "pukatakana"; + psod_glyphs[0x33B4] = "pvsquare"; + psod_glyphs[0x33BA] = "pwsquare"; + psod_glyphs[0x0071] = "q"; + psod_glyphs[0x0958] = "qadeva"; + psod_glyphs[0x05A8] = "qadmahebrew"; + psod_glyphs[0x0642] = "qafarabic"; + psod_glyphs[0xFED6] = "qaffinalarabic"; + psod_glyphs[0xFED7] = "qafinitialarabic"; + psod_glyphs[0xFED8] = "qafmedialarabic"; + psod_glyphs[0x05B8] = "qamats"; + //psod_glyphs[0x05B8] = "qamats10"; + //psod_glyphs[0x05B8] = "qamats1a"; + //psod_glyphs[0x05B8] = "qamats1c"; + //psod_glyphs[0x05B8] = "qamats27"; + //psod_glyphs[0x05B8] = "qamats29"; + //psod_glyphs[0x05B8] = "qamats33"; + //psod_glyphs[0x05B8] = "qamatsde"; + //psod_glyphs[0x05B8] = "qamatshebrew"; + //psod_glyphs[0x05B8] = "qamatsnarrowhebrew"; + //psod_glyphs[0x05B8] = "qamatsqatanhebrew"; + //psod_glyphs[0x05B8] = "qamatsqatannarrowhebrew"; + //psod_glyphs[0x05B8] = "qamatsqatanquarterhebrew"; + //psod_glyphs[0x05B8] = "qamatsqatanwidehebrew"; + //psod_glyphs[0x05B8] = "qamatsquarterhebrew"; + //psod_glyphs[0x05B8] = "qamatswidehebrew"; + psod_glyphs[0x059F] = "qarneyparahebrew"; + psod_glyphs[0x3111] = "qbopomofo"; + psod_glyphs[0x24E0] = "qcircle"; + psod_glyphs[0x02A0] = "qhook"; + psod_glyphs[0xFF51] = "qmonospace"; + psod_glyphs[0x05E7] = "qof"; + psod_glyphs[0xFB47] = "qofdagesh"; + psod_glyphs[0xFB47] = "qofdageshhebrew"; + //psod_glyphs[0x05E7 05B2] = "qofhatafpatah"; + //psod_glyphs[0x05E7 05B2] = "qofhatafpatahhebrew"; + //psod_glyphs[0x05E7 05B1] = "qofhatafsegol"; + //psod_glyphs[0x05E7 05B1] = "qofhatafsegolhebrew"; + psod_glyphs[0x05E7] = "qofhebrew"; + //psod_glyphs[0x05E7 05B4] = "qofhiriq"; + //psod_glyphs[0x05E7 05B4] = "qofhiriqhebrew"; + //psod_glyphs[0x05E7 05B9] = "qofholam"; + //psod_glyphs[0x05E7 05B9] = "qofholamhebrew"; + //psod_glyphs[0x05E7 05B7] = "qofpatah"; + //psod_glyphs[0x05E7 05B7] = "qofpatahhebrew"; + //psod_glyphs[0x05E7 05B8] = "qofqamats"; + //psod_glyphs[0x05E7 05B8] = "qofqamatshebrew"; + //psod_glyphs[0x05E7 05BB] = "qofqubuts"; + //psod_glyphs[0x05E7 05BB] = "qofqubutshebrew"; + //psod_glyphs[0x05E7 05B6] = "qofsegol"; + //psod_glyphs[0x05E7 05B6] = "qofsegolhebrew"; + //psod_glyphs[0x05E7 05B0] = "qofsheva"; + //psod_glyphs[0x05E7 05B0] = "qofshevahebrew"; + //psod_glyphs[0x05E7 05B5] = "qoftsere"; + //psod_glyphs[0x05E7 05B5] = "qoftserehebrew"; + psod_glyphs[0x24AC] = "qparen"; + psod_glyphs[0x2669] = "quarternote"; + psod_glyphs[0x05BB] = "qubuts"; + //psod_glyphs[0x05BB] = "qubuts18"; + //psod_glyphs[0x05BB] = "qubuts25"; + //psod_glyphs[0x05BB] = "qubuts31"; + //psod_glyphs[0x05BB] = "qubutshebrew"; + //psod_glyphs[0x05BB] = "qubutsnarrowhebrew"; + //psod_glyphs[0x05BB] = "qubutsquarterhebrew"; + //psod_glyphs[0x05BB] = "qubutswidehebrew"; + psod_glyphs[0x003F] = "question"; + psod_glyphs[0x061F] = "questionarabic"; + psod_glyphs[0x055E] = "questionarmenian"; + psod_glyphs[0x00BF] = "questiondown"; + psod_glyphs[0xF7BF] = "questiondownsmall"; + psod_glyphs[0x037E] = "questiongreek"; + psod_glyphs[0xFF1F] = "questionmonospace"; + psod_glyphs[0xF73F] = "questionsmall"; + psod_glyphs[0x0022] = "quotedbl"; + psod_glyphs[0x201E] = "quotedblbase"; + psod_glyphs[0x201C] = "quotedblleft"; + psod_glyphs[0xFF02] = "quotedblmonospace"; + psod_glyphs[0x301E] = "quotedblprime"; + psod_glyphs[0x301D] = "quotedblprimereversed"; + psod_glyphs[0x201D] = "quotedblright"; + psod_glyphs[0x2018] = "quoteleft"; + psod_glyphs[0x201B] = "quoteleftreversed"; + psod_glyphs[0x201B] = "quotereversed"; + psod_glyphs[0x2019] = "quoteright"; + psod_glyphs[0x0149] = "quoterightn"; + psod_glyphs[0x201A] = "quotesinglbase"; + psod_glyphs[0x0027] = "quotesingle"; + psod_glyphs[0xFF07] = "quotesinglemonospace"; + psod_glyphs[0x0072] = "r"; + psod_glyphs[0x057C] = "raarmenian"; + psod_glyphs[0x09B0] = "rabengali"; + psod_glyphs[0x0155] = "racute"; + psod_glyphs[0x0930] = "radeva"; + psod_glyphs[0x221A] = "radical"; + psod_glyphs[0xF8E5] = "radicalex"; + psod_glyphs[0x33AE] = "radoverssquare"; + psod_glyphs[0x33AF] = "radoverssquaredsquare"; + psod_glyphs[0x33AD] = "radsquare"; + psod_glyphs[0x05BF] = "rafe"; + //psod_glyphs[0x05BF] = "rafehebrew"; + psod_glyphs[0x0AB0] = "ragujarati"; + psod_glyphs[0x0A30] = "ragurmukhi"; + psod_glyphs[0x3089] = "rahiragana"; + psod_glyphs[0x30E9] = "rakatakana"; + psod_glyphs[0xFF97] = "rakatakanahalfwidth"; + psod_glyphs[0x09F1] = "ralowerdiagonalbengali"; + psod_glyphs[0x09F0] = "ramiddlediagonalbengali"; + psod_glyphs[0x0264] = "ramshorn"; + psod_glyphs[0x2236] = "ratio"; + psod_glyphs[0x3116] = "rbopomofo"; + psod_glyphs[0x0159] = "rcaron"; + psod_glyphs[0x0157] = "rcedilla"; + psod_glyphs[0x24E1] = "rcircle"; + psod_glyphs[0x0157] = "rcommaaccent"; + psod_glyphs[0x0211] = "rdblgrave"; + psod_glyphs[0x1E59] = "rdotaccent"; + psod_glyphs[0x1E5B] = "rdotbelow"; + psod_glyphs[0x1E5D] = "rdotbelowmacron"; + psod_glyphs[0x203B] = "referencemark"; + psod_glyphs[0x2286] = "reflexsubset"; + psod_glyphs[0x2287] = "reflexsuperset"; + psod_glyphs[0x00AE] = "registered"; + psod_glyphs[0xF8E8] = "registersans"; + psod_glyphs[0xF6DA] = "registerserif"; + psod_glyphs[0x0631] = "reharabic"; + psod_glyphs[0x0580] = "reharmenian"; + psod_glyphs[0xFEAE] = "rehfinalarabic"; + psod_glyphs[0x308C] = "rehiragana"; + //psod_glyphs[0x0631 FEF3 FE8E 0644] = "rehyehaleflamarabic"; + psod_glyphs[0x30EC] = "rekatakana"; + psod_glyphs[0xFF9A] = "rekatakanahalfwidth"; + psod_glyphs[0x05E8] = "resh"; + psod_glyphs[0xFB48] = "reshdageshhebrew"; + //psod_glyphs[0x05E8 05B2] = "reshhatafpatah"; + //psod_glyphs[0x05E8 05B2] = "reshhatafpatahhebrew"; + //psod_glyphs[0x05E8 05B1] = "reshhatafsegol"; + //psod_glyphs[0x05E8 05B1] = "reshhatafsegolhebrew"; + psod_glyphs[0x05E8] = "reshhebrew"; + //psod_glyphs[0x05E8 05B4] = "reshhiriq"; + //psod_glyphs[0x05E8 05B4] = "reshhiriqhebrew"; + //psod_glyphs[0x05E8 05B9] = "reshholam"; + //psod_glyphs[0x05E8 05B9] = "reshholamhebrew"; + //psod_glyphs[0x05E8 05B7] = "reshpatah"; + //psod_glyphs[0x05E8 05B7] = "reshpatahhebrew"; + //psod_glyphs[0x05E8 05B8] = "reshqamats"; + //psod_glyphs[0x05E8 05B8] = "reshqamatshebrew"; + //psod_glyphs[0x05E8 05BB] = "reshqubuts"; + //psod_glyphs[0x05E8 05BB] = "reshqubutshebrew"; + //psod_glyphs[0x05E8 05B6] = "reshsegol"; + //psod_glyphs[0x05E8 05B6] = "reshsegolhebrew"; + //psod_glyphs[0x05E8 05B0] = "reshsheva"; + //psod_glyphs[0x05E8 05B0] = "reshshevahebrew"; + //psod_glyphs[0x05E8 05B5] = "reshtsere"; + //psod_glyphs[0x05E8 05B5] = "reshtserehebrew"; + psod_glyphs[0x223D] = "reversedtilde"; + psod_glyphs[0x0597] = "reviahebrew"; + psod_glyphs[0x0597] = "reviamugrashhebrew"; + psod_glyphs[0x2310] = "revlogicalnot"; + psod_glyphs[0x027E] = "rfishhook"; + psod_glyphs[0x027F] = "rfishhookreversed"; + psod_glyphs[0x09DD] = "rhabengali"; + psod_glyphs[0x095D] = "rhadeva"; + psod_glyphs[0x03C1] = "rho"; + psod_glyphs[0x027D] = "rhook"; + psod_glyphs[0x027B] = "rhookturned"; + psod_glyphs[0x02B5] = "rhookturnedsuperior"; + psod_glyphs[0x03F1] = "rhosymbolgreek"; + psod_glyphs[0x02DE] = "rhotichookmod"; + psod_glyphs[0x3271] = "rieulacirclekorean"; + psod_glyphs[0x3211] = "rieulaparenkorean"; + psod_glyphs[0x3263] = "rieulcirclekorean"; + psod_glyphs[0x3140] = "rieulhieuhkorean"; + psod_glyphs[0x313A] = "rieulkiyeokkorean"; + psod_glyphs[0x3169] = "rieulkiyeoksioskorean"; + psod_glyphs[0x3139] = "rieulkorean"; + psod_glyphs[0x313B] = "rieulmieumkorean"; + psod_glyphs[0x316C] = "rieulpansioskorean"; + psod_glyphs[0x3203] = "rieulparenkorean"; + psod_glyphs[0x313F] = "rieulphieuphkorean"; + psod_glyphs[0x313C] = "rieulpieupkorean"; + psod_glyphs[0x316B] = "rieulpieupsioskorean"; + psod_glyphs[0x313D] = "rieulsioskorean"; + psod_glyphs[0x313E] = "rieulthieuthkorean"; + psod_glyphs[0x316A] = "rieultikeutkorean"; + psod_glyphs[0x316D] = "rieulyeorinhieuhkorean"; + psod_glyphs[0x221F] = "rightangle"; + psod_glyphs[0x0319] = "righttackbelowcmb"; + psod_glyphs[0x22BF] = "righttriangle"; + psod_glyphs[0x308A] = "rihiragana"; + psod_glyphs[0x30EA] = "rikatakana"; + psod_glyphs[0xFF98] = "rikatakanahalfwidth"; + psod_glyphs[0x02DA] = "ring"; + psod_glyphs[0x0325] = "ringbelowcmb"; + psod_glyphs[0x030A] = "ringcmb"; + psod_glyphs[0x02BF] = "ringhalfleft"; + psod_glyphs[0x0559] = "ringhalfleftarmenian"; + psod_glyphs[0x031C] = "ringhalfleftbelowcmb"; + psod_glyphs[0x02D3] = "ringhalfleftcentered"; + psod_glyphs[0x02BE] = "ringhalfright"; + psod_glyphs[0x0339] = "ringhalfrightbelowcmb"; + psod_glyphs[0x02D2] = "ringhalfrightcentered"; + psod_glyphs[0x0213] = "rinvertedbreve"; + psod_glyphs[0x3351] = "rittorusquare"; + psod_glyphs[0x1E5F] = "rlinebelow"; + psod_glyphs[0x027C] = "rlongleg"; + psod_glyphs[0x027A] = "rlonglegturned"; + psod_glyphs[0xFF52] = "rmonospace"; + psod_glyphs[0x308D] = "rohiragana"; + psod_glyphs[0x30ED] = "rokatakana"; + psod_glyphs[0xFF9B] = "rokatakanahalfwidth"; + psod_glyphs[0x0E23] = "roruathai"; + psod_glyphs[0x24AD] = "rparen"; + psod_glyphs[0x09DC] = "rrabengali"; + psod_glyphs[0x0931] = "rradeva"; + psod_glyphs[0x0A5C] = "rragurmukhi"; + psod_glyphs[0x0691] = "rreharabic"; + psod_glyphs[0xFB8D] = "rrehfinalarabic"; + psod_glyphs[0x09E0] = "rrvocalicbengali"; + psod_glyphs[0x0960] = "rrvocalicdeva"; + psod_glyphs[0x0AE0] = "rrvocalicgujarati"; + psod_glyphs[0x09C4] = "rrvocalicvowelsignbengali"; + psod_glyphs[0x0944] = "rrvocalicvowelsigndeva"; + psod_glyphs[0x0AC4] = "rrvocalicvowelsigngujarati"; + psod_glyphs[0xF6F1] = "rsuperior"; + psod_glyphs[0x2590] = "rtblock"; + psod_glyphs[0x0279] = "rturned"; + psod_glyphs[0x02B4] = "rturnedsuperior"; + psod_glyphs[0x308B] = "ruhiragana"; + psod_glyphs[0x30EB] = "rukatakana"; + psod_glyphs[0xFF99] = "rukatakanahalfwidth"; + psod_glyphs[0x09F2] = "rupeemarkbengali"; + psod_glyphs[0x09F3] = "rupeesignbengali"; + psod_glyphs[0xF6DD] = "rupiah"; + psod_glyphs[0x0E24] = "ruthai"; + psod_glyphs[0x098B] = "rvocalicbengali"; + psod_glyphs[0x090B] = "rvocalicdeva"; + psod_glyphs[0x0A8B] = "rvocalicgujarati"; + psod_glyphs[0x09C3] = "rvocalicvowelsignbengali"; + psod_glyphs[0x0943] = "rvocalicvowelsigndeva"; + psod_glyphs[0x0AC3] = "rvocalicvowelsigngujarati"; + psod_glyphs[0x0073] = "s"; + psod_glyphs[0x09B8] = "sabengali"; + psod_glyphs[0x015B] = "sacute"; + psod_glyphs[0x1E65] = "sacutedotaccent"; + psod_glyphs[0x0635] = "sadarabic"; + psod_glyphs[0x0938] = "sadeva"; + psod_glyphs[0xFEBA] = "sadfinalarabic"; + psod_glyphs[0xFEBB] = "sadinitialarabic"; + psod_glyphs[0xFEBC] = "sadmedialarabic"; + psod_glyphs[0x0AB8] = "sagujarati"; + psod_glyphs[0x0A38] = "sagurmukhi"; + psod_glyphs[0x3055] = "sahiragana"; + psod_glyphs[0x30B5] = "sakatakana"; + psod_glyphs[0xFF7B] = "sakatakanahalfwidth"; + psod_glyphs[0xFDFA] = "sallallahoualayhewasallamarabic"; + psod_glyphs[0x05E1] = "samekh"; + psod_glyphs[0xFB41] = "samekhdagesh"; + psod_glyphs[0xFB41] = "samekhdageshhebrew"; + psod_glyphs[0x05E1] = "samekhhebrew"; + psod_glyphs[0x0E32] = "saraaathai"; + psod_glyphs[0x0E41] = "saraaethai"; + psod_glyphs[0x0E44] = "saraaimaimalaithai"; + psod_glyphs[0x0E43] = "saraaimaimuanthai"; + psod_glyphs[0x0E33] = "saraamthai"; + psod_glyphs[0x0E30] = "saraathai"; + psod_glyphs[0x0E40] = "saraethai"; + psod_glyphs[0xF886] = "saraiileftthai"; + psod_glyphs[0x0E35] = "saraiithai"; + psod_glyphs[0xF885] = "saraileftthai"; + psod_glyphs[0x0E34] = "saraithai"; + psod_glyphs[0x0E42] = "saraothai"; + psod_glyphs[0xF888] = "saraueeleftthai"; + psod_glyphs[0x0E37] = "saraueethai"; + psod_glyphs[0xF887] = "saraueleftthai"; + psod_glyphs[0x0E36] = "sarauethai"; + psod_glyphs[0x0E38] = "sarauthai"; + psod_glyphs[0x0E39] = "sarauuthai"; + psod_glyphs[0x3119] = "sbopomofo"; + psod_glyphs[0x0161] = "scaron"; + psod_glyphs[0x1E67] = "scarondotaccent"; + psod_glyphs[0x015F] = "scedilla"; + psod_glyphs[0x0259] = "schwa"; + psod_glyphs[0x04D9] = "schwacyrillic"; + psod_glyphs[0x04DB] = "schwadieresiscyrillic"; + psod_glyphs[0x025A] = "schwahook"; + psod_glyphs[0x24E2] = "scircle"; + psod_glyphs[0x015D] = "scircumflex"; + psod_glyphs[0x0219] = "scommaaccent"; + psod_glyphs[0x1E61] = "sdotaccent"; + psod_glyphs[0x1E63] = "sdotbelow"; + psod_glyphs[0x1E69] = "sdotbelowdotaccent"; + psod_glyphs[0x033C] = "seagullbelowcmb"; + psod_glyphs[0x2033] = "second"; + psod_glyphs[0x02CA] = "secondtonechinese"; + psod_glyphs[0x00A7] = "section"; + psod_glyphs[0x0633] = "seenarabic"; + psod_glyphs[0xFEB2] = "seenfinalarabic"; + psod_glyphs[0xFEB3] = "seeninitialarabic"; + psod_glyphs[0xFEB4] = "seenmedialarabic"; + psod_glyphs[0x05B6] = "segol"; + //psod_glyphs[0x05B6] = "segol13"; + //psod_glyphs[0x05B6] = "segol1f"; + //psod_glyphs[0x05B6] = "segol2c"; + //psod_glyphs[0x05B6] = "segolhebrew"; + //psod_glyphs[0x05B6] = "segolnarrowhebrew"; + //psod_glyphs[0x05B6] = "segolquarterhebrew"; + psod_glyphs[0x0592] = "segoltahebrew"; + //psod_glyphs[0x05B6] = "segolwidehebrew"; + psod_glyphs[0x057D] = "seharmenian"; + psod_glyphs[0x305B] = "sehiragana"; + psod_glyphs[0x30BB] = "sekatakana"; + psod_glyphs[0xFF7E] = "sekatakanahalfwidth"; + psod_glyphs[0x003B] = "semicolon"; + psod_glyphs[0x061B] = "semicolonarabic"; + psod_glyphs[0xFF1B] = "semicolonmonospace"; + psod_glyphs[0xFE54] = "semicolonsmall"; + psod_glyphs[0x309C] = "semivoicedmarkkana"; + psod_glyphs[0xFF9F] = "semivoicedmarkkanahalfwidth"; + psod_glyphs[0x3322] = "sentisquare"; + psod_glyphs[0x3323] = "sentosquare"; + psod_glyphs[0x0037] = "seven"; + psod_glyphs[0x0667] = "sevenarabic"; + psod_glyphs[0x09ED] = "sevenbengali"; + psod_glyphs[0x2466] = "sevencircle"; + psod_glyphs[0x2790] = "sevencircleinversesansserif"; + psod_glyphs[0x096D] = "sevendeva"; + psod_glyphs[0x215E] = "seveneighths"; + psod_glyphs[0x0AED] = "sevengujarati"; + psod_glyphs[0x0A6D] = "sevengurmukhi"; + psod_glyphs[0x0667] = "sevenhackarabic"; + psod_glyphs[0x3027] = "sevenhangzhou"; + psod_glyphs[0x3226] = "sevenideographicparen"; + psod_glyphs[0x2087] = "seveninferior"; + psod_glyphs[0xFF17] = "sevenmonospace"; + psod_glyphs[0xF737] = "sevenoldstyle"; + psod_glyphs[0x247A] = "sevenparen"; + psod_glyphs[0x248E] = "sevenperiod"; + psod_glyphs[0x06F7] = "sevenpersian"; + psod_glyphs[0x2176] = "sevenroman"; + psod_glyphs[0x2077] = "sevensuperior"; + psod_glyphs[0x2470] = "seventeencircle"; + psod_glyphs[0x2484] = "seventeenparen"; + psod_glyphs[0x2498] = "seventeenperiod"; + psod_glyphs[0x0E57] = "seventhai"; + //psod_glyphs[0x00AD] = "sfthyphen"; + psod_glyphs[0x0577] = "shaarmenian"; + psod_glyphs[0x09B6] = "shabengali"; + psod_glyphs[0x0448] = "shacyrillic"; + psod_glyphs[0x0651] = "shaddaarabic"; + psod_glyphs[0xFC61] = "shaddadammaarabic"; + psod_glyphs[0xFC5E] = "shaddadammatanarabic"; + psod_glyphs[0xFC60] = "shaddafathaarabic"; + //psod_glyphs[0x0651 064B] = "shaddafathatanarabic"; + psod_glyphs[0xFC62] = "shaddakasraarabic"; + psod_glyphs[0xFC5F] = "shaddakasratanarabic"; + psod_glyphs[0x2592] = "shade"; + psod_glyphs[0x2593] = "shadedark"; + psod_glyphs[0x2591] = "shadelight"; + psod_glyphs[0x2592] = "shademedium"; + psod_glyphs[0x0936] = "shadeva"; + psod_glyphs[0x0AB6] = "shagujarati"; + psod_glyphs[0x0A36] = "shagurmukhi"; + psod_glyphs[0x0593] = "shalshelethebrew"; + psod_glyphs[0x3115] = "shbopomofo"; + psod_glyphs[0x0449] = "shchacyrillic"; + psod_glyphs[0x0634] = "sheenarabic"; + psod_glyphs[0xFEB6] = "sheenfinalarabic"; + psod_glyphs[0xFEB7] = "sheeninitialarabic"; + psod_glyphs[0xFEB8] = "sheenmedialarabic"; + psod_glyphs[0x03E3] = "sheicoptic"; + psod_glyphs[0x20AA] = "sheqel"; + //psod_glyphs[0x20AA] = "sheqelhebrew"; + psod_glyphs[0x05B0] = "sheva"; + //psod_glyphs[0x05B0] = "sheva115"; + //psod_glyphs[0x05B0] = "sheva15"; + //psod_glyphs[0x05B0] = "sheva22"; + //psod_glyphs[0x05B0] = "sheva2e"; + //psod_glyphs[0x05B0] = "shevahebrew"; + //psod_glyphs[0x05B0] = "shevanarrowhebrew"; + //psod_glyphs[0x05B0] = "shevaquarterhebrew"; + //psod_glyphs[0x05B0] = "shevawidehebrew"; + psod_glyphs[0x04BB] = "shhacyrillic"; + psod_glyphs[0x03ED] = "shimacoptic"; + psod_glyphs[0x05E9] = "shin"; + psod_glyphs[0xFB49] = "shindagesh"; + //psod_glyphs[0xFB49] = "shindageshhebrew"; + psod_glyphs[0xFB2C] = "shindageshshindot"; + //psod_glyphs[0xFB2C] = "shindageshshindothebrew"; + psod_glyphs[0xFB2D] = "shindageshsindot"; + //psod_glyphs[0xFB2D] = "shindageshsindothebrew"; + psod_glyphs[0x05C1] = "shindothebrew"; + psod_glyphs[0x05E9] = "shinhebrew"; + psod_glyphs[0xFB2A] = "shinshindot"; + //psod_glyphs[0xFB2A] = "shinshindothebrew"; + psod_glyphs[0xFB2B] = "shinsindot"; + //psod_glyphs[0xFB2B] = "shinsindothebrew"; + psod_glyphs[0x0282] = "shook"; + psod_glyphs[0x03C3] = "sigma"; + psod_glyphs[0x03C2] = "sigma1"; + //psod_glyphs[0x03C2] = "sigmafinal"; + psod_glyphs[0x03F2] = "sigmalunatesymbolgreek"; + psod_glyphs[0x3057] = "sihiragana"; + psod_glyphs[0x30B7] = "sikatakana"; + psod_glyphs[0xFF7C] = "sikatakanahalfwidth"; + psod_glyphs[0x05BD] = "siluqhebrew"; + //psod_glyphs[0x05BD] = "siluqlefthebrew"; + psod_glyphs[0x223C] = "similar"; + psod_glyphs[0x05C2] = "sindothebrew"; + psod_glyphs[0x3274] = "siosacirclekorean"; + psod_glyphs[0x3214] = "siosaparenkorean"; + psod_glyphs[0x317E] = "sioscieuckorean"; + psod_glyphs[0x3266] = "sioscirclekorean"; + psod_glyphs[0x317A] = "sioskiyeokkorean"; + psod_glyphs[0x3145] = "sioskorean"; + psod_glyphs[0x317B] = "siosnieunkorean"; + psod_glyphs[0x3206] = "siosparenkorean"; + psod_glyphs[0x317D] = "siospieupkorean"; + psod_glyphs[0x317C] = "siostikeutkorean"; + psod_glyphs[0x0036] = "six"; + psod_glyphs[0x0666] = "sixarabic"; + psod_glyphs[0x09EC] = "sixbengali"; + psod_glyphs[0x2465] = "sixcircle"; + psod_glyphs[0x278F] = "sixcircleinversesansserif"; + psod_glyphs[0x096C] = "sixdeva"; + psod_glyphs[0x0AEC] = "sixgujarati"; + psod_glyphs[0x0A6C] = "sixgurmukhi"; + psod_glyphs[0x0666] = "sixhackarabic"; + psod_glyphs[0x3026] = "sixhangzhou"; + psod_glyphs[0x3225] = "sixideographicparen"; + psod_glyphs[0x2086] = "sixinferior"; + psod_glyphs[0xFF16] = "sixmonospace"; + psod_glyphs[0xF736] = "sixoldstyle"; + psod_glyphs[0x2479] = "sixparen"; + psod_glyphs[0x248D] = "sixperiod"; + psod_glyphs[0x06F6] = "sixpersian"; + psod_glyphs[0x2175] = "sixroman"; + psod_glyphs[0x2076] = "sixsuperior"; + psod_glyphs[0x246F] = "sixteencircle"; + psod_glyphs[0x09F9] = "sixteencurrencydenominatorbengali"; + psod_glyphs[0x2483] = "sixteenparen"; + psod_glyphs[0x2497] = "sixteenperiod"; + psod_glyphs[0x0E56] = "sixthai"; + psod_glyphs[0x002F] = "slash"; + psod_glyphs[0xFF0F] = "slashmonospace"; + psod_glyphs[0x017F] = "slong"; + psod_glyphs[0x1E9B] = "slongdotaccent"; + psod_glyphs[0x263A] = "smileface"; + psod_glyphs[0xFF53] = "smonospace"; + psod_glyphs[0x05C3] = "sofpasuqhebrew"; + psod_glyphs[0x00AD] = "softhyphen"; + psod_glyphs[0x044C] = "softsigncyrillic"; + psod_glyphs[0x305D] = "sohiragana"; + psod_glyphs[0x30BD] = "sokatakana"; + psod_glyphs[0xFF7F] = "sokatakanahalfwidth"; + psod_glyphs[0x0338] = "soliduslongoverlaycmb"; + psod_glyphs[0x0337] = "solidusshortoverlaycmb"; + psod_glyphs[0x0E29] = "sorusithai"; + psod_glyphs[0x0E28] = "sosalathai"; + psod_glyphs[0x0E0B] = "sosothai"; + psod_glyphs[0x0E2A] = "sosuathai"; + psod_glyphs[0x0020] = "space"; + //psod_glyphs[0x0020] = "spacehackarabic"; + psod_glyphs[0x2660] = "spade"; + //psod_glyphs[0x2660] = "spadesuitblack"; + psod_glyphs[0x2664] = "spadesuitwhite"; + psod_glyphs[0x24AE] = "sparen"; + psod_glyphs[0x033B] = "squarebelowcmb"; + psod_glyphs[0x33C4] = "squarecc"; + psod_glyphs[0x339D] = "squarecm"; + psod_glyphs[0x25A9] = "squarediagonalcrosshatchfill"; + psod_glyphs[0x25A4] = "squarehorizontalfill"; + psod_glyphs[0x338F] = "squarekg"; + psod_glyphs[0x339E] = "squarekm"; + psod_glyphs[0x33CE] = "squarekmcapital"; + psod_glyphs[0x33D1] = "squareln"; + psod_glyphs[0x33D2] = "squarelog"; + psod_glyphs[0x338E] = "squaremg"; + psod_glyphs[0x33D5] = "squaremil"; + psod_glyphs[0x339C] = "squaremm"; + psod_glyphs[0x33A1] = "squaremsquared"; + psod_glyphs[0x25A6] = "squareorthogonalcrosshatchfill"; + psod_glyphs[0x25A7] = "squareupperlefttolowerrightfill"; + psod_glyphs[0x25A8] = "squareupperrighttolowerleftfill"; + psod_glyphs[0x25A5] = "squareverticalfill"; + psod_glyphs[0x25A3] = "squarewhitewithsmallblack"; + psod_glyphs[0x33DB] = "srsquare"; + psod_glyphs[0x09B7] = "ssabengali"; + psod_glyphs[0x0937] = "ssadeva"; + psod_glyphs[0x0AB7] = "ssagujarati"; + psod_glyphs[0x3149] = "ssangcieuckorean"; + psod_glyphs[0x3185] = "ssanghieuhkorean"; + psod_glyphs[0x3180] = "ssangieungkorean"; + psod_glyphs[0x3132] = "ssangkiyeokkorean"; + psod_glyphs[0x3165] = "ssangnieunkorean"; + psod_glyphs[0x3143] = "ssangpieupkorean"; + psod_glyphs[0x3146] = "ssangsioskorean"; + psod_glyphs[0x3138] = "ssangtikeutkorean"; + psod_glyphs[0xF6F2] = "ssuperior"; + psod_glyphs[0x00A3] = "sterling"; + psod_glyphs[0xFFE1] = "sterlingmonospace"; + psod_glyphs[0x0336] = "strokelongoverlaycmb"; + psod_glyphs[0x0335] = "strokeshortoverlaycmb"; + psod_glyphs[0x2282] = "subset"; + psod_glyphs[0x228A] = "subsetnotequal"; + psod_glyphs[0x2286] = "subsetorequal"; + psod_glyphs[0x227B] = "succeeds"; + psod_glyphs[0x220B] = "suchthat"; + psod_glyphs[0x3059] = "suhiragana"; + psod_glyphs[0x30B9] = "sukatakana"; + psod_glyphs[0xFF7D] = "sukatakanahalfwidth"; + psod_glyphs[0x0652] = "sukunarabic"; + psod_glyphs[0x2211] = "summation"; + psod_glyphs[0x263C] = "sun"; + psod_glyphs[0x2283] = "superset"; + psod_glyphs[0x228B] = "supersetnotequal"; + psod_glyphs[0x2287] = "supersetorequal"; + psod_glyphs[0x33DC] = "svsquare"; + psod_glyphs[0x337C] = "syouwaerasquare"; + psod_glyphs[0x0074] = "t"; + psod_glyphs[0x09A4] = "tabengali"; + psod_glyphs[0x22A4] = "tackdown"; + psod_glyphs[0x22A3] = "tackleft"; + psod_glyphs[0x0924] = "tadeva"; + psod_glyphs[0x0AA4] = "tagujarati"; + psod_glyphs[0x0A24] = "tagurmukhi"; + psod_glyphs[0x0637] = "taharabic"; + psod_glyphs[0xFEC2] = "tahfinalarabic"; + psod_glyphs[0xFEC3] = "tahinitialarabic"; + psod_glyphs[0x305F] = "tahiragana"; + psod_glyphs[0xFEC4] = "tahmedialarabic"; + psod_glyphs[0x337D] = "taisyouerasquare"; + psod_glyphs[0x30BF] = "takatakana"; + psod_glyphs[0xFF80] = "takatakanahalfwidth"; + psod_glyphs[0x0640] = "tatweelarabic"; + psod_glyphs[0x03C4] = "tau"; + psod_glyphs[0x05EA] = "tav"; + psod_glyphs[0xFB4A] = "tavdages"; + psod_glyphs[0xFB4A] = "tavdagesh"; + psod_glyphs[0xFB4A] = "tavdageshhebrew"; + psod_glyphs[0x05EA] = "tavhebrew"; + psod_glyphs[0x0167] = "tbar"; + psod_glyphs[0x310A] = "tbopomofo"; + psod_glyphs[0x0165] = "tcaron"; + psod_glyphs[0x02A8] = "tccurl"; + psod_glyphs[0x0163] = "tcedilla"; + psod_glyphs[0x0686] = "tcheharabic"; + psod_glyphs[0xFB7B] = "tchehfinalarabic"; + psod_glyphs[0xFB7C] = "tchehinitialarabic"; + psod_glyphs[0xFB7D] = "tchehmedialarabic"; + //psod_glyphs[0xFB7C FEE4] = "tchehmeeminitialarabic"; + psod_glyphs[0x24E3] = "tcircle"; + psod_glyphs[0x1E71] = "tcircumflexbelow"; + psod_glyphs[0x0163] = "tcommaaccent"; + psod_glyphs[0x1E97] = "tdieresis"; + psod_glyphs[0x1E6B] = "tdotaccent"; + psod_glyphs[0x1E6D] = "tdotbelow"; + psod_glyphs[0x0442] = "tecyrillic"; + psod_glyphs[0x04AD] = "tedescendercyrillic"; + psod_glyphs[0x062A] = "teharabic"; + psod_glyphs[0xFE96] = "tehfinalarabic"; + psod_glyphs[0xFCA2] = "tehhahinitialarabic"; + psod_glyphs[0xFC0C] = "tehhahisolatedarabic"; + psod_glyphs[0xFE97] = "tehinitialarabic"; + psod_glyphs[0x3066] = "tehiragana"; + psod_glyphs[0xFCA1] = "tehjeeminitialarabic"; + psod_glyphs[0xFC0B] = "tehjeemisolatedarabic"; + psod_glyphs[0x0629] = "tehmarbutaarabic"; + psod_glyphs[0xFE94] = "tehmarbutafinalarabic"; + psod_glyphs[0xFE98] = "tehmedialarabic"; + psod_glyphs[0xFCA4] = "tehmeeminitialarabic"; + psod_glyphs[0xFC0E] = "tehmeemisolatedarabic"; + psod_glyphs[0xFC73] = "tehnoonfinalarabic"; + psod_glyphs[0x30C6] = "tekatakana"; + psod_glyphs[0xFF83] = "tekatakanahalfwidth"; + psod_glyphs[0x2121] = "telephone"; + psod_glyphs[0x260E] = "telephoneblack"; + psod_glyphs[0x05A0] = "telishagedolahebrew"; + psod_glyphs[0x05A9] = "telishaqetanahebrew"; + psod_glyphs[0x2469] = "tencircle"; + psod_glyphs[0x3229] = "tenideographicparen"; + psod_glyphs[0x247D] = "tenparen"; + psod_glyphs[0x2491] = "tenperiod"; + psod_glyphs[0x2179] = "tenroman"; + psod_glyphs[0x02A7] = "tesh"; + psod_glyphs[0x05D8] = "tet"; + psod_glyphs[0xFB38] = "tetdagesh"; + psod_glyphs[0xFB38] = "tetdageshhebrew"; + psod_glyphs[0x05D8] = "tethebrew"; + psod_glyphs[0x04B5] = "tetsecyrillic"; + psod_glyphs[0x059B] = "tevirhebrew"; + psod_glyphs[0x059B] = "tevirlefthebrew"; + psod_glyphs[0x09A5] = "thabengali"; + psod_glyphs[0x0925] = "thadeva"; + psod_glyphs[0x0AA5] = "thagujarati"; + psod_glyphs[0x0A25] = "thagurmukhi"; + psod_glyphs[0x0630] = "thalarabic"; + psod_glyphs[0xFEAC] = "thalfinalarabic"; + psod_glyphs[0xF898] = "thanthakhatlowleftthai"; + psod_glyphs[0xF897] = "thanthakhatlowrightthai"; + psod_glyphs[0x0E4C] = "thanthakhatthai"; + psod_glyphs[0xF896] = "thanthakhatupperleftthai"; + psod_glyphs[0x062B] = "theharabic"; + psod_glyphs[0xFE9A] = "thehfinalarabic"; + psod_glyphs[0xFE9B] = "thehinitialarabic"; + psod_glyphs[0xFE9C] = "thehmedialarabic"; + psod_glyphs[0x2203] = "thereexists"; + psod_glyphs[0x2234] = "therefore"; + psod_glyphs[0x03B8] = "theta"; + psod_glyphs[0x03D1] = "theta1"; + psod_glyphs[0x03D1] = "thetasymbolgreek"; + psod_glyphs[0x3279] = "thieuthacirclekorean"; + psod_glyphs[0x3219] = "thieuthaparenkorean"; + psod_glyphs[0x326B] = "thieuthcirclekorean"; + psod_glyphs[0x314C] = "thieuthkorean"; + psod_glyphs[0x320B] = "thieuthparenkorean"; + psod_glyphs[0x246C] = "thirteencircle"; + psod_glyphs[0x2480] = "thirteenparen"; + psod_glyphs[0x2494] = "thirteenperiod"; + psod_glyphs[0x0E11] = "thonangmonthothai"; + psod_glyphs[0x01AD] = "thook"; + psod_glyphs[0x0E12] = "thophuthaothai"; + psod_glyphs[0x00FE] = "thorn"; + psod_glyphs[0x0E17] = "thothahanthai"; + psod_glyphs[0x0E10] = "thothanthai"; + psod_glyphs[0x0E18] = "thothongthai"; + psod_glyphs[0x0E16] = "thothungthai"; + psod_glyphs[0x0482] = "thousandcyrillic"; + psod_glyphs[0x066C] = "thousandsseparatorarabic"; + psod_glyphs[0x066C] = "thousandsseparatorpersian"; + psod_glyphs[0x0033] = "three"; + psod_glyphs[0x0663] = "threearabic"; + psod_glyphs[0x09E9] = "threebengali"; + psod_glyphs[0x2462] = "threecircle"; + psod_glyphs[0x278C] = "threecircleinversesansserif"; + psod_glyphs[0x0969] = "threedeva"; + psod_glyphs[0x215C] = "threeeighths"; + psod_glyphs[0x0AE9] = "threegujarati"; + psod_glyphs[0x0A69] = "threegurmukhi"; + psod_glyphs[0x0663] = "threehackarabic"; + psod_glyphs[0x3023] = "threehangzhou"; + psod_glyphs[0x3222] = "threeideographicparen"; + psod_glyphs[0x2083] = "threeinferior"; + psod_glyphs[0xFF13] = "threemonospace"; + psod_glyphs[0x09F6] = "threenumeratorbengali"; + psod_glyphs[0xF733] = "threeoldstyle"; + psod_glyphs[0x2476] = "threeparen"; + psod_glyphs[0x248A] = "threeperiod"; + psod_glyphs[0x06F3] = "threepersian"; + psod_glyphs[0x00BE] = "threequarters"; + psod_glyphs[0xF6DE] = "threequartersemdash"; + psod_glyphs[0x2172] = "threeroman"; + psod_glyphs[0x00B3] = "threesuperior"; + psod_glyphs[0x0E53] = "threethai"; + psod_glyphs[0x3394] = "thzsquare"; + psod_glyphs[0x3061] = "tihiragana"; + psod_glyphs[0x30C1] = "tikatakana"; + psod_glyphs[0xFF81] = "tikatakanahalfwidth"; + psod_glyphs[0x3270] = "tikeutacirclekorean"; + psod_glyphs[0x3210] = "tikeutaparenkorean"; + psod_glyphs[0x3262] = "tikeutcirclekorean"; + psod_glyphs[0x3137] = "tikeutkorean"; + psod_glyphs[0x3202] = "tikeutparenkorean"; + psod_glyphs[0x02DC] = "tilde"; + psod_glyphs[0x0330] = "tildebelowcmb"; + psod_glyphs[0x0303] = "tildecmb"; + psod_glyphs[0x0303] = "tildecomb"; + psod_glyphs[0x0360] = "tildedoublecmb"; + psod_glyphs[0x223C] = "tildeoperator"; + psod_glyphs[0x0334] = "tildeoverlaycmb"; + psod_glyphs[0x033E] = "tildeverticalcmb"; + psod_glyphs[0x2297] = "timescircle"; + psod_glyphs[0x0596] = "tipehahebrew"; + psod_glyphs[0x0596] = "tipehalefthebrew"; + psod_glyphs[0x0A70] = "tippigurmukhi"; + psod_glyphs[0x0483] = "titlocyrilliccmb"; + psod_glyphs[0x057F] = "tiwnarmenian"; + psod_glyphs[0x1E6F] = "tlinebelow"; + psod_glyphs[0xFF54] = "tmonospace"; + psod_glyphs[0x0569] = "toarmenian"; + psod_glyphs[0x3068] = "tohiragana"; + psod_glyphs[0x30C8] = "tokatakana"; + psod_glyphs[0xFF84] = "tokatakanahalfwidth"; + psod_glyphs[0x02E5] = "tonebarextrahighmod"; + psod_glyphs[0x02E9] = "tonebarextralowmod"; + psod_glyphs[0x02E6] = "tonebarhighmod"; + psod_glyphs[0x02E8] = "tonebarlowmod"; + psod_glyphs[0x02E7] = "tonebarmidmod"; + psod_glyphs[0x01BD] = "tonefive"; + psod_glyphs[0x0185] = "tonesix"; + psod_glyphs[0x01A8] = "tonetwo"; + psod_glyphs[0x0384] = "tonos"; + psod_glyphs[0x3327] = "tonsquare"; + psod_glyphs[0x0E0F] = "topatakthai"; + psod_glyphs[0x3014] = "tortoiseshellbracketleft"; + psod_glyphs[0xFE5D] = "tortoiseshellbracketleftsmall"; + psod_glyphs[0xFE39] = "tortoiseshellbracketleftvertical"; + psod_glyphs[0x3015] = "tortoiseshellbracketright"; + psod_glyphs[0xFE5E] = "tortoiseshellbracketrightsmall"; + psod_glyphs[0xFE3A] = "tortoiseshellbracketrightvertical"; + psod_glyphs[0x0E15] = "totaothai"; + psod_glyphs[0x01AB] = "tpalatalhook"; + psod_glyphs[0x24AF] = "tparen"; + psod_glyphs[0x2122] = "trademark"; + psod_glyphs[0xF8EA] = "trademarksans"; + psod_glyphs[0xF6DB] = "trademarkserif"; + psod_glyphs[0x0288] = "tretroflexhook"; + psod_glyphs[0x25BC] = "triagdn"; + psod_glyphs[0x25C4] = "triaglf"; + psod_glyphs[0x25BA] = "triagrt"; + psod_glyphs[0x25B2] = "triagup"; + psod_glyphs[0x02A6] = "ts"; + psod_glyphs[0x05E6] = "tsadi"; + psod_glyphs[0xFB46] = "tsadidagesh"; + psod_glyphs[0xFB46] = "tsadidageshhebrew"; + psod_glyphs[0x05E6] = "tsadihebrew"; + psod_glyphs[0x0446] = "tsecyrillic"; + psod_glyphs[0x05B5] = "tsere"; + //psod_glyphs[0x05B5] = "tsere12"; + //psod_glyphs[0x05B5] = "tsere1e"; + //psod_glyphs[0x05B5] = "tsere2b"; + //psod_glyphs[0x05B5] = "tserehebrew"; + //psod_glyphs[0x05B5] = "tserenarrowhebrew"; + //psod_glyphs[0x05B5] = "tserequarterhebrew"; + //psod_glyphs[0x05B5] = "tserewidehebrew"; + psod_glyphs[0x045B] = "tshecyrillic"; + psod_glyphs[0xF6F3] = "tsuperior"; + psod_glyphs[0x099F] = "ttabengali"; + psod_glyphs[0x091F] = "ttadeva"; + psod_glyphs[0x0A9F] = "ttagujarati"; + psod_glyphs[0x0A1F] = "ttagurmukhi"; + psod_glyphs[0x0679] = "tteharabic"; + psod_glyphs[0xFB67] = "ttehfinalarabic"; + psod_glyphs[0xFB68] = "ttehinitialarabic"; + psod_glyphs[0xFB69] = "ttehmedialarabic"; + psod_glyphs[0x09A0] = "tthabengali"; + psod_glyphs[0x0920] = "tthadeva"; + psod_glyphs[0x0AA0] = "tthagujarati"; + psod_glyphs[0x0A20] = "tthagurmukhi"; + psod_glyphs[0x0287] = "tturned"; + psod_glyphs[0x3064] = "tuhiragana"; + psod_glyphs[0x30C4] = "tukatakana"; + psod_glyphs[0xFF82] = "tukatakanahalfwidth"; + psod_glyphs[0x3063] = "tusmallhiragana"; + psod_glyphs[0x30C3] = "tusmallkatakana"; + psod_glyphs[0xFF6F] = "tusmallkatakanahalfwidth"; + psod_glyphs[0x246B] = "twelvecircle"; + psod_glyphs[0x247F] = "twelveparen"; + psod_glyphs[0x2493] = "twelveperiod"; + psod_glyphs[0x217B] = "twelveroman"; + psod_glyphs[0x2473] = "twentycircle"; + psod_glyphs[0x5344] = "twentyhangzhou"; + psod_glyphs[0x2487] = "twentyparen"; + psod_glyphs[0x249B] = "twentyperiod"; + psod_glyphs[0x0032] = "two"; + psod_glyphs[0x0662] = "twoarabic"; + psod_glyphs[0x09E8] = "twobengali"; + psod_glyphs[0x2461] = "twocircle"; + psod_glyphs[0x278B] = "twocircleinversesansserif"; + psod_glyphs[0x0968] = "twodeva"; + psod_glyphs[0x2025] = "twodotenleader"; + psod_glyphs[0x2025] = "twodotleader"; + psod_glyphs[0xFE30] = "twodotleadervertical"; + psod_glyphs[0x0AE8] = "twogujarati"; + psod_glyphs[0x0A68] = "twogurmukhi"; + psod_glyphs[0x0662] = "twohackarabic"; + psod_glyphs[0x3022] = "twohangzhou"; + psod_glyphs[0x3221] = "twoideographicparen"; + psod_glyphs[0x2082] = "twoinferior"; + psod_glyphs[0xFF12] = "twomonospace"; + psod_glyphs[0x09F5] = "twonumeratorbengali"; + psod_glyphs[0xF732] = "twooldstyle"; + psod_glyphs[0x2475] = "twoparen"; + psod_glyphs[0x2489] = "twoperiod"; + psod_glyphs[0x06F2] = "twopersian"; + psod_glyphs[0x2171] = "tworoman"; + psod_glyphs[0x01BB] = "twostroke"; + psod_glyphs[0x00B2] = "twosuperior"; + psod_glyphs[0x0E52] = "twothai"; + psod_glyphs[0x2154] = "twothirds"; + psod_glyphs[0x0075] = "u"; + psod_glyphs[0x00FA] = "uacute"; + psod_glyphs[0x0289] = "ubar"; + psod_glyphs[0x0989] = "ubengali"; + psod_glyphs[0x3128] = "ubopomofo"; + psod_glyphs[0x016D] = "ubreve"; + psod_glyphs[0x01D4] = "ucaron"; + psod_glyphs[0x24E4] = "ucircle"; + psod_glyphs[0x00FB] = "ucircumflex"; + psod_glyphs[0x1E77] = "ucircumflexbelow"; + psod_glyphs[0x0443] = "ucyrillic"; + psod_glyphs[0x0951] = "udattadeva"; + psod_glyphs[0x0171] = "udblacute"; + psod_glyphs[0x0215] = "udblgrave"; + psod_glyphs[0x0909] = "udeva"; + psod_glyphs[0x00FC] = "udieresis"; + psod_glyphs[0x01D8] = "udieresisacute"; + psod_glyphs[0x1E73] = "udieresisbelow"; + psod_glyphs[0x01DA] = "udieresiscaron"; + psod_glyphs[0x04F1] = "udieresiscyrillic"; + psod_glyphs[0x01DC] = "udieresisgrave"; + psod_glyphs[0x01D6] = "udieresismacron"; + psod_glyphs[0x1EE5] = "udotbelow"; + psod_glyphs[0x00F9] = "ugrave"; + psod_glyphs[0x0A89] = "ugujarati"; + psod_glyphs[0x0A09] = "ugurmukhi"; + psod_glyphs[0x3046] = "uhiragana"; + psod_glyphs[0x1EE7] = "uhookabove"; + psod_glyphs[0x01B0] = "uhorn"; + psod_glyphs[0x1EE9] = "uhornacute"; + psod_glyphs[0x1EF1] = "uhorndotbelow"; + psod_glyphs[0x1EEB] = "uhorngrave"; + psod_glyphs[0x1EED] = "uhornhookabove"; + psod_glyphs[0x1EEF] = "uhorntilde"; + psod_glyphs[0x0171] = "uhungarumlaut"; + psod_glyphs[0x04F3] = "uhungarumlautcyrillic"; + psod_glyphs[0x0217] = "uinvertedbreve"; + psod_glyphs[0x30A6] = "ukatakana"; + psod_glyphs[0xFF73] = "ukatakanahalfwidth"; + psod_glyphs[0x0479] = "ukcyrillic"; + psod_glyphs[0x315C] = "ukorean"; + psod_glyphs[0x016B] = "umacron"; + psod_glyphs[0x04EF] = "umacroncyrillic"; + psod_glyphs[0x1E7B] = "umacrondieresis"; + psod_glyphs[0x0A41] = "umatragurmukhi"; + psod_glyphs[0xFF55] = "umonospace"; + psod_glyphs[0x005F] = "underscore"; + psod_glyphs[0x2017] = "underscoredbl"; + psod_glyphs[0xFF3F] = "underscoremonospace"; + psod_glyphs[0xFE33] = "underscorevertical"; + psod_glyphs[0xFE4F] = "underscorewavy"; + psod_glyphs[0x222A] = "union"; + psod_glyphs[0x2200] = "universal"; + psod_glyphs[0x0173] = "uogonek"; + psod_glyphs[0x24B0] = "uparen"; + psod_glyphs[0x2580] = "upblock"; + psod_glyphs[0x05C4] = "upperdothebrew"; + psod_glyphs[0x03C5] = "upsilon"; + psod_glyphs[0x03CB] = "upsilondieresis"; + psod_glyphs[0x03B0] = "upsilondieresistonos"; + psod_glyphs[0x028A] = "upsilonlatin"; + psod_glyphs[0x03CD] = "upsilontonos"; + psod_glyphs[0x031D] = "uptackbelowcmb"; + psod_glyphs[0x02D4] = "uptackmod"; + psod_glyphs[0x0A73] = "uragurmukhi"; + psod_glyphs[0x016F] = "uring"; + psod_glyphs[0x045E] = "ushortcyrillic"; + psod_glyphs[0x3045] = "usmallhiragana"; + psod_glyphs[0x30A5] = "usmallkatakana"; + psod_glyphs[0xFF69] = "usmallkatakanahalfwidth"; + psod_glyphs[0x04AF] = "ustraightcyrillic"; + psod_glyphs[0x04B1] = "ustraightstrokecyrillic"; + psod_glyphs[0x0169] = "utilde"; + psod_glyphs[0x1E79] = "utildeacute"; + psod_glyphs[0x1E75] = "utildebelow"; + psod_glyphs[0x098A] = "uubengali"; + psod_glyphs[0x090A] = "uudeva"; + psod_glyphs[0x0A8A] = "uugujarati"; + psod_glyphs[0x0A0A] = "uugurmukhi"; + psod_glyphs[0x0A42] = "uumatragurmukhi"; + psod_glyphs[0x09C2] = "uuvowelsignbengali"; + psod_glyphs[0x0942] = "uuvowelsigndeva"; + psod_glyphs[0x0AC2] = "uuvowelsigngujarati"; + psod_glyphs[0x09C1] = "uvowelsignbengali"; + psod_glyphs[0x0941] = "uvowelsigndeva"; + psod_glyphs[0x0AC1] = "uvowelsigngujarati"; + psod_glyphs[0x0076] = "v"; + psod_glyphs[0x0935] = "vadeva"; + psod_glyphs[0x0AB5] = "vagujarati"; + psod_glyphs[0x0A35] = "vagurmukhi"; + psod_glyphs[0x30F7] = "vakatakana"; + psod_glyphs[0x05D5] = "vav"; + psod_glyphs[0xFB35] = "vavdagesh"; + psod_glyphs[0xFB35] = "vavdagesh65"; + psod_glyphs[0xFB35] = "vavdageshhebrew"; + psod_glyphs[0x05D5] = "vavhebrew"; + psod_glyphs[0xFB4B] = "vavholam"; + psod_glyphs[0xFB4B] = "vavholamhebrew"; + psod_glyphs[0x05F0] = "vavvavhebrew"; + psod_glyphs[0x05F1] = "vavyodhebrew"; + psod_glyphs[0x24E5] = "vcircle"; + psod_glyphs[0x1E7F] = "vdotbelow"; + psod_glyphs[0x0432] = "vecyrillic"; + psod_glyphs[0x06A4] = "veharabic"; + psod_glyphs[0xFB6B] = "vehfinalarabic"; + psod_glyphs[0xFB6C] = "vehinitialarabic"; + psod_glyphs[0xFB6D] = "vehmedialarabic"; + psod_glyphs[0x30F9] = "vekatakana"; + psod_glyphs[0x2640] = "venus"; + //psod_glyphs[0x007C] = "verticalbar"; + psod_glyphs[0x030D] = "verticallineabovecmb"; + psod_glyphs[0x0329] = "verticallinebelowcmb"; + psod_glyphs[0x02CC] = "verticallinelowmod"; + psod_glyphs[0x02C8] = "verticallinemod"; + psod_glyphs[0x057E] = "vewarmenian"; + psod_glyphs[0x028B] = "vhook"; + psod_glyphs[0x30F8] = "vikatakana"; + psod_glyphs[0x09CD] = "viramabengali"; + psod_glyphs[0x094D] = "viramadeva"; + psod_glyphs[0x0ACD] = "viramagujarati"; + psod_glyphs[0x0983] = "visargabengali"; + psod_glyphs[0x0903] = "visargadeva"; + psod_glyphs[0x0A83] = "visargagujarati"; + psod_glyphs[0xFF56] = "vmonospace"; + psod_glyphs[0x0578] = "voarmenian"; + psod_glyphs[0x309E] = "voicediterationhiragana"; + psod_glyphs[0x30FE] = "voicediterationkatakana"; + psod_glyphs[0x309B] = "voicedmarkkana"; + psod_glyphs[0xFF9E] = "voicedmarkkanahalfwidth"; + psod_glyphs[0x30FA] = "vokatakana"; + psod_glyphs[0x24B1] = "vparen"; + psod_glyphs[0x1E7D] = "vtilde"; + psod_glyphs[0x028C] = "vturned"; + psod_glyphs[0x3094] = "vuhiragana"; + psod_glyphs[0x30F4] = "vukatakana"; + psod_glyphs[0x0077] = "w"; + psod_glyphs[0x1E83] = "wacute"; + psod_glyphs[0x3159] = "waekorean"; + psod_glyphs[0x308F] = "wahiragana"; + psod_glyphs[0x30EF] = "wakatakana"; + psod_glyphs[0xFF9C] = "wakatakanahalfwidth"; + psod_glyphs[0x3158] = "wakorean"; + psod_glyphs[0x308E] = "wasmallhiragana"; + psod_glyphs[0x30EE] = "wasmallkatakana"; + psod_glyphs[0x3357] = "wattosquare"; + psod_glyphs[0x301C] = "wavedash"; + psod_glyphs[0xFE34] = "wavyunderscorevertical"; + psod_glyphs[0x0648] = "wawarabic"; + psod_glyphs[0xFEEE] = "wawfinalarabic"; + psod_glyphs[0x0624] = "wawhamzaabovearabic"; + psod_glyphs[0xFE86] = "wawhamzaabovefinalarabic"; + psod_glyphs[0x33DD] = "wbsquare"; + psod_glyphs[0x24E6] = "wcircle"; + psod_glyphs[0x0175] = "wcircumflex"; + psod_glyphs[0x1E85] = "wdieresis"; + psod_glyphs[0x1E87] = "wdotaccent"; + psod_glyphs[0x1E89] = "wdotbelow"; + psod_glyphs[0x3091] = "wehiragana"; + psod_glyphs[0x2118] = "weierstrass"; + psod_glyphs[0x30F1] = "wekatakana"; + psod_glyphs[0x315E] = "wekorean"; + psod_glyphs[0x315D] = "weokorean"; + psod_glyphs[0x1E81] = "wgrave"; + psod_glyphs[0x25E6] = "whitebullet"; + psod_glyphs[0x25CB] = "whitecircle"; + psod_glyphs[0x25D9] = "whitecircleinverse"; + psod_glyphs[0x300E] = "whitecornerbracketleft"; + psod_glyphs[0xFE43] = "whitecornerbracketleftvertical"; + psod_glyphs[0x300F] = "whitecornerbracketright"; + psod_glyphs[0xFE44] = "whitecornerbracketrightvertical"; + psod_glyphs[0x25C7] = "whitediamond"; + psod_glyphs[0x25C8] = "whitediamondcontainingblacksmalldiamond"; + psod_glyphs[0x25BF] = "whitedownpointingsmalltriangle"; + psod_glyphs[0x25BD] = "whitedownpointingtriangle"; + psod_glyphs[0x25C3] = "whiteleftpointingsmalltriangle"; + psod_glyphs[0x25C1] = "whiteleftpointingtriangle"; + psod_glyphs[0x3016] = "whitelenticularbracketleft"; + psod_glyphs[0x3017] = "whitelenticularbracketright"; + psod_glyphs[0x25B9] = "whiterightpointingsmalltriangle"; + psod_glyphs[0x25B7] = "whiterightpointingtriangle"; + psod_glyphs[0x25AB] = "whitesmallsquare"; + psod_glyphs[0x263A] = "whitesmilingface"; + psod_glyphs[0x25A1] = "whitesquare"; + psod_glyphs[0x2606] = "whitestar"; + psod_glyphs[0x260F] = "whitetelephone"; + psod_glyphs[0x3018] = "whitetortoiseshellbracketleft"; + psod_glyphs[0x3019] = "whitetortoiseshellbracketright"; + psod_glyphs[0x25B5] = "whiteuppointingsmalltriangle"; + psod_glyphs[0x25B3] = "whiteuppointingtriangle"; + psod_glyphs[0x3090] = "wihiragana"; + psod_glyphs[0x30F0] = "wikatakana"; + psod_glyphs[0x315F] = "wikorean"; + psod_glyphs[0xFF57] = "wmonospace"; + psod_glyphs[0x3092] = "wohiragana"; + psod_glyphs[0x30F2] = "wokatakana"; + psod_glyphs[0xFF66] = "wokatakanahalfwidth"; + psod_glyphs[0x20A9] = "won"; + psod_glyphs[0xFFE6] = "wonmonospace"; + psod_glyphs[0x0E27] = "wowaenthai"; + psod_glyphs[0x24B2] = "wparen"; + psod_glyphs[0x1E98] = "wring"; + psod_glyphs[0x02B7] = "wsuperior"; + psod_glyphs[0x028D] = "wturned"; + psod_glyphs[0x01BF] = "wynn"; + psod_glyphs[0x0078] = "x"; + psod_glyphs[0x033D] = "xabovecmb"; + psod_glyphs[0x3112] = "xbopomofo"; + psod_glyphs[0x24E7] = "xcircle"; + psod_glyphs[0x1E8D] = "xdieresis"; + psod_glyphs[0x1E8B] = "xdotaccent"; + psod_glyphs[0x056D] = "xeharmenian"; + psod_glyphs[0x03BE] = "xi"; + psod_glyphs[0xFF58] = "xmonospace"; + psod_glyphs[0x24B3] = "xparen"; + psod_glyphs[0x02E3] = "xsuperior"; + psod_glyphs[0x0079] = "y"; + psod_glyphs[0x334E] = "yaadosquare"; + psod_glyphs[0x09AF] = "yabengali"; + psod_glyphs[0x00FD] = "yacute"; + psod_glyphs[0x092F] = "yadeva"; + psod_glyphs[0x3152] = "yaekorean"; + psod_glyphs[0x0AAF] = "yagujarati"; + psod_glyphs[0x0A2F] = "yagurmukhi"; + psod_glyphs[0x3084] = "yahiragana"; + psod_glyphs[0x30E4] = "yakatakana"; + psod_glyphs[0xFF94] = "yakatakanahalfwidth"; + psod_glyphs[0x3151] = "yakorean"; + psod_glyphs[0x0E4E] = "yamakkanthai"; + psod_glyphs[0x3083] = "yasmallhiragana"; + psod_glyphs[0x30E3] = "yasmallkatakana"; + psod_glyphs[0xFF6C] = "yasmallkatakanahalfwidth"; + psod_glyphs[0x0463] = "yatcyrillic"; + psod_glyphs[0x24E8] = "ycircle"; + psod_glyphs[0x0177] = "ycircumflex"; + psod_glyphs[0x00FF] = "ydieresis"; + psod_glyphs[0x1E8F] = "ydotaccent"; + psod_glyphs[0x1EF5] = "ydotbelow"; + psod_glyphs[0x064A] = "yeharabic"; + psod_glyphs[0x06D2] = "yehbarreearabic"; + psod_glyphs[0xFBAF] = "yehbarreefinalarabic"; + psod_glyphs[0xFEF2] = "yehfinalarabic"; + psod_glyphs[0x0626] = "yehhamzaabovearabic"; + psod_glyphs[0xFE8A] = "yehhamzaabovefinalarabic"; + psod_glyphs[0xFE8B] = "yehhamzaaboveinitialarabic"; + psod_glyphs[0xFE8C] = "yehhamzaabovemedialarabic"; + psod_glyphs[0xFEF3] = "yehinitialarabic"; + psod_glyphs[0xFEF4] = "yehmedialarabic"; + psod_glyphs[0xFCDD] = "yehmeeminitialarabic"; + psod_glyphs[0xFC58] = "yehmeemisolatedarabic"; + psod_glyphs[0xFC94] = "yehnoonfinalarabic"; + psod_glyphs[0x06D1] = "yehthreedotsbelowarabic"; + psod_glyphs[0x3156] = "yekorean"; + psod_glyphs[0x00A5] = "yen"; + psod_glyphs[0xFFE5] = "yenmonospace"; + psod_glyphs[0x3155] = "yeokorean"; + psod_glyphs[0x3186] = "yeorinhieuhkorean"; + psod_glyphs[0x05AA] = "yerahbenyomohebrew"; + psod_glyphs[0x05AA] = "yerahbenyomolefthebrew"; + psod_glyphs[0x044B] = "yericyrillic"; + psod_glyphs[0x04F9] = "yerudieresiscyrillic"; + psod_glyphs[0x3181] = "yesieungkorean"; + psod_glyphs[0x3183] = "yesieungpansioskorean"; + psod_glyphs[0x3182] = "yesieungsioskorean"; + psod_glyphs[0x059A] = "yetivhebrew"; + psod_glyphs[0x1EF3] = "ygrave"; + psod_glyphs[0x01B4] = "yhook"; + psod_glyphs[0x1EF7] = "yhookabove"; + psod_glyphs[0x0575] = "yiarmenian"; + psod_glyphs[0x0457] = "yicyrillic"; + psod_glyphs[0x3162] = "yikorean"; + psod_glyphs[0x262F] = "yinyang"; + psod_glyphs[0x0582] = "yiwnarmenian"; + psod_glyphs[0xFF59] = "ymonospace"; + psod_glyphs[0x05D9] = "yod"; + psod_glyphs[0xFB39] = "yoddagesh"; + psod_glyphs[0xFB39] = "yoddageshhebrew"; + psod_glyphs[0x05D9] = "yodhebrew"; + psod_glyphs[0x05F2] = "yodyodhebrew"; + psod_glyphs[0xFB1F] = "yodyodpatahhebrew"; + psod_glyphs[0x3088] = "yohiragana"; + psod_glyphs[0x3189] = "yoikorean"; + psod_glyphs[0x30E8] = "yokatakana"; + psod_glyphs[0xFF96] = "yokatakanahalfwidth"; + psod_glyphs[0x315B] = "yokorean"; + psod_glyphs[0x3087] = "yosmallhiragana"; + psod_glyphs[0x30E7] = "yosmallkatakana"; + psod_glyphs[0xFF6E] = "yosmallkatakanahalfwidth"; + psod_glyphs[0x03F3] = "yotgreek"; + psod_glyphs[0x3188] = "yoyaekorean"; + psod_glyphs[0x3187] = "yoyakorean"; + psod_glyphs[0x0E22] = "yoyakthai"; + psod_glyphs[0x0E0D] = "yoyingthai"; + psod_glyphs[0x24B4] = "yparen"; + psod_glyphs[0x037A] = "ypogegrammeni"; + psod_glyphs[0x0345] = "ypogegrammenigreekcmb"; + psod_glyphs[0x01A6] = "yr"; + psod_glyphs[0x1E99] = "yring"; + psod_glyphs[0x02B8] = "ysuperior"; + psod_glyphs[0x1EF9] = "ytilde"; + psod_glyphs[0x028E] = "yturned"; + psod_glyphs[0x3086] = "yuhiragana"; + psod_glyphs[0x318C] = "yuikorean"; + psod_glyphs[0x30E6] = "yukatakana"; + psod_glyphs[0xFF95] = "yukatakanahalfwidth"; + psod_glyphs[0x3160] = "yukorean"; + psod_glyphs[0x046B] = "yusbigcyrillic"; + psod_glyphs[0x046D] = "yusbigiotifiedcyrillic"; + psod_glyphs[0x0467] = "yuslittlecyrillic"; + psod_glyphs[0x0469] = "yuslittleiotifiedcyrillic"; + psod_glyphs[0x3085] = "yusmallhiragana"; + psod_glyphs[0x30E5] = "yusmallkatakana"; + psod_glyphs[0xFF6D] = "yusmallkatakanahalfwidth"; + psod_glyphs[0x318B] = "yuyekorean"; + psod_glyphs[0x318A] = "yuyeokorean"; + psod_glyphs[0x09DF] = "yyabengali"; + psod_glyphs[0x095F] = "yyadeva"; + psod_glyphs[0x007A] = "z"; + psod_glyphs[0x0566] = "zaarmenian"; + psod_glyphs[0x017A] = "zacute"; + psod_glyphs[0x095B] = "zadeva"; + psod_glyphs[0x0A5B] = "zagurmukhi"; + psod_glyphs[0x0638] = "zaharabic"; + psod_glyphs[0xFEC6] = "zahfinalarabic"; + psod_glyphs[0xFEC7] = "zahinitialarabic"; + psod_glyphs[0x3056] = "zahiragana"; + psod_glyphs[0xFEC8] = "zahmedialarabic"; + psod_glyphs[0x0632] = "zainarabic"; + psod_glyphs[0xFEB0] = "zainfinalarabic"; + psod_glyphs[0x30B6] = "zakatakana"; + psod_glyphs[0x0595] = "zaqefgadolhebrew"; + psod_glyphs[0x0594] = "zaqefqatanhebrew"; + psod_glyphs[0x0598] = "zarqahebrew"; + psod_glyphs[0x05D6] = "zayin"; + psod_glyphs[0xFB36] = "zayindagesh"; + psod_glyphs[0xFB36] = "zayindageshhebrew"; + psod_glyphs[0x05D6] = "zayinhebrew"; + psod_glyphs[0x3117] = "zbopomofo"; + psod_glyphs[0x017E] = "zcaron"; + psod_glyphs[0x24E9] = "zcircle"; + psod_glyphs[0x1E91] = "zcircumflex"; + psod_glyphs[0x0291] = "zcurl"; + psod_glyphs[0x017C] = "zdot"; + psod_glyphs[0x017C] = "zdotaccent"; + psod_glyphs[0x1E93] = "zdotbelow"; + psod_glyphs[0x0437] = "zecyrillic"; + psod_glyphs[0x0499] = "zedescendercyrillic"; + psod_glyphs[0x04DF] = "zedieresiscyrillic"; + psod_glyphs[0x305C] = "zehiragana"; + psod_glyphs[0x30BC] = "zekatakana"; + psod_glyphs[0x0030] = "zero"; + psod_glyphs[0x0660] = "zeroarabic"; + psod_glyphs[0x09E6] = "zerobengali"; + psod_glyphs[0x0966] = "zerodeva"; + psod_glyphs[0x0AE6] = "zerogujarati"; + psod_glyphs[0x0A66] = "zerogurmukhi"; + psod_glyphs[0x0660] = "zerohackarabic"; + psod_glyphs[0x2080] = "zeroinferior"; + psod_glyphs[0xFF10] = "zeromonospace"; + psod_glyphs[0xF730] = "zerooldstyle"; + psod_glyphs[0x06F0] = "zeropersian"; + psod_glyphs[0x2070] = "zerosuperior"; + psod_glyphs[0x0E50] = "zerothai"; + psod_glyphs[0xFEFF] = "zerowidthjoiner"; + psod_glyphs[0x200C] = "zerowidthnonjoiner"; + psod_glyphs[0x200B] = "zerowidthspace"; + psod_glyphs[0x03B6] = "zeta"; + psod_glyphs[0x3113] = "zhbopomofo"; + psod_glyphs[0x056A] = "zhearmenian"; + psod_glyphs[0x04C2] = "zhebrevecyrillic"; + psod_glyphs[0x0436] = "zhecyrillic"; + psod_glyphs[0x0497] = "zhedescendercyrillic"; + psod_glyphs[0x04DD] = "zhedieresiscyrillic"; + psod_glyphs[0x3058] = "zihiragana"; + psod_glyphs[0x30B8] = "zikatakana"; + psod_glyphs[0x05AE] = "zinorhebrew"; + psod_glyphs[0x1E95] = "zlinebelow"; + psod_glyphs[0xFF5A] = "zmonospace"; + psod_glyphs[0x305E] = "zohiragana"; + psod_glyphs[0x30BE] = "zokatakana"; + psod_glyphs[0x24B5] = "zparen"; + psod_glyphs[0x0290] = "zretroflexhook"; + psod_glyphs[0x01B6] = "zstroke"; + psod_glyphs[0x305A] = "zuhiragana"; + psod_glyphs[0x30BA] = "zukatakana"; + + return 0; + } From 669631aaf7487c75b3aebc2b89b1e038f9412c0e Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Mon, 10 Oct 2011 12:08:44 -0600 Subject: [PATCH 022/124] Adding interim UTF-8 support in GetCharacterMetric (font metrics work needed) - This commit causes the server to count UTF-8 encoded characters properly as just one character. However, we are still not looking up the correct font metric -- only the lower ASCII codes have proper font metrics in the server (grr). --- centrallix/report/prtmgmt_v3_fm_html.c | 10 +++++++++- centrallix/report/prtmgmt_v3_internal.c | 3 ++- centrallix/report/prtmgmt_v3_od_ps.c | 11 ++++++++++- centrallix/report/prtmgmt_v3_od_text.c | 25 +++++++++++++++++++++++-- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 8c4fcb3f7..d1d4bbae8 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -346,7 +346,15 @@ prt_htmlfm_GetCharacterMetric(void* context_v, char* str, pPrtTextStyle style, d n = 0.0; while(*str) { - if (*str < 0x20 || *str > 0x7E) + if (((unsigned char*)str)[0] > 0x7F && CxGlobals.CharacterMode == CharModeUTF8) + { + /** UTF-8 encoded character, skip entire encoded char. **/ + str++; + n += 1.0; + while ((((unsigned char*)str)[0] & 0xC0) == 0x80) + str++; + } + else if (*str < 0x20 || *str > 0x7E) n += 1.0; else if (style->FontID == PRT_FONT_T_SANSSERIF) n += prt_htmlfm_helvetica_font_metrics[(*str) - 0x20][a]/60.0; diff --git a/centrallix/report/prtmgmt_v3_internal.c b/centrallix/report/prtmgmt_v3_internal.c index 6ccc82ea7..1a44f2100 100644 --- a/centrallix/report/prtmgmt_v3_internal.c +++ b/centrallix/report/prtmgmt_v3_internal.c @@ -444,7 +444,8 @@ prt_internal_GetFontBaseline(pPrtObjStream obj) /*** prt_internal_GetStringWidth - obtain, via char metrics, the physical - *** width of the given string of text. + *** width of the given string of text. is in bytes, not in characters + *** (this is singificant if the string is UTF-8 encoded). ***/ double prt_internal_GetStringWidth(pPrtObjStream obj, char* str, int n) diff --git a/centrallix/report/prtmgmt_v3_od_ps.c b/centrallix/report/prtmgmt_v3_od_ps.c index 254fdd494..df9bedce2 100644 --- a/centrallix/report/prtmgmt_v3_od_ps.c +++ b/centrallix/report/prtmgmt_v3_od_ps.c @@ -9,6 +9,7 @@ #include #include #include +#include "centrallix.h" #include "barcode.h" #include "report.h" #include "cxlib/mtask.h" @@ -691,7 +692,15 @@ prt_psod_GetCharacterMetric(void* context_v, unsigned char* str, pPrtTextStyle s n = 0.0; while(*str) { - if (*str < 0x20 || *str > 0x7E) + if (str[0] > 0x7F && CxGlobals.CharacterMode == CharModeUTF8) + { + /** UTF-8 encoded character, count entire encoded char as one. **/ + str++; + n += 1.0; + while ((str[0] & 0xC0) == 0x80) + str++; + } + else if (*str < 0x20 || *str > 0x7E) { /** No data for characters outside the range; assume 1.0 **/ n += 1.0; diff --git a/centrallix/report/prtmgmt_v3_od_text.c b/centrallix/report/prtmgmt_v3_od_text.c index 917aa2246..e535177e0 100644 --- a/centrallix/report/prtmgmt_v3_od_text.c +++ b/centrallix/report/prtmgmt_v3_od_text.c @@ -4,6 +4,7 @@ #include #include #include +#include "centrallix.h" #include "barcode.h" #include "report.h" #include "cxlib/mtask.h" @@ -359,8 +360,28 @@ void prt_textod_GetCharacterMetric(void* context_v, unsigned char* str, pPrtTextStyle style, double* width, double* height) { /*pPrtTextodInf context = (pPrtTextodInf)context_v;*/ - *width = strlen((char*)str); - *height = 1; + double n = 0.0; + + while(*str) + { + if (str[0] > 0x7F && CxGlobals.CharacterMode == CharModeUTF8) + { + /** UTF-8 encoded character, skip entire encoded char. **/ + str++; + n += 1.0; + while ((str[0] & 0xC0) == 0x80) + str++; + } + else + { + str++; + n += 1.0; + } + } + + *width = n; + *height = 1; + return; } From c864c53b698c8f76938620cd643c45f5120849d7 Mon Sep 17 00:00:00 2001 From: Greg Beeley Date: Mon, 10 Oct 2011 12:47:32 -0600 Subject: [PATCH 023/124] Bugfix for character metric in UTF8; word wrapping for UTF8. --- centrallix/report/prtmgmt_v3_fm_html.c | 3 +-- centrallix/report/prtmgmt_v3_lm_text.c | 34 ++++++++++++++++++++++++-- centrallix/report/prtmgmt_v3_od_ps.c | 3 +-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index d1d4bbae8..a81a19c80 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -349,9 +349,8 @@ prt_htmlfm_GetCharacterMetric(void* context_v, char* str, pPrtTextStyle style, d if (((unsigned char*)str)[0] > 0x7F && CxGlobals.CharacterMode == CharModeUTF8) { /** UTF-8 encoded character, skip entire encoded char. **/ - str++; n += 1.0; - while ((((unsigned char*)str)[0] & 0xC0) == 0x80) + while ((((unsigned char*)str)[1] & 0xC0) == 0x80) str++; } else if (*str < 0x20 || *str > 0x7E) diff --git a/centrallix/report/prtmgmt_v3_lm_text.c b/centrallix/report/prtmgmt_v3_lm_text.c index ba704ff0a..ca2d9a648 100644 --- a/centrallix/report/prtmgmt_v3_lm_text.c +++ b/centrallix/report/prtmgmt_v3_lm_text.c @@ -4,6 +4,7 @@ #include #include #include +#include "centrallix.h" #include "barcode.h" #include "report.h" #include "cxlib/mtask.h" @@ -582,6 +583,30 @@ prt_textlm_JustifyLine(pPrtObjStream starting_point, int jtype) } +/*** prt_textlm_BytesForChar() - determine the number of bytes the given + *** character uses. In UTF-8 mode, this is variable. Otherwise, it is + *** just 1 byte (we do not support UTF-16 or UCS-2). + ***/ +int +prt_textlm_BytesForChar(unsigned char* str) + { + int n; + + if (str[0] > 0x7F && CxGlobals.CharacterMode == CharModeUTF8) + { + n = 1; + while ((str[n] & 0xC0) == 0x80) + n++; + } + else + { + n = 1; + } + + return n; + } + + /*** prt_textlm_FindWrapPoint() - finds a suitable location within a given *** string object to break it in order to do word wrapping. Basically, *** a hyphen or a space makes a wrap point. This function will find the @@ -596,6 +621,7 @@ prt_textlm_FindWrapPoint(pPrtObjStream stringobj, double maxwidth, int* brkpoint { int sl,n,last_sep,sw; double lastw, w, ckw; + int n_bytes; /** If empty, we can't wrap it!! **/ if (stringobj->Content[0] == '\0') @@ -610,7 +636,8 @@ prt_textlm_FindWrapPoint(pPrtObjStream stringobj, double maxwidth, int* brkpoint sl = strlen((char*)stringobj->Content); last_sep = -1; lastw = 0.0; - for(n=0;nContent[n] == ' ' || (n > 1 && stringobj->Content[n-1] == '-' && stringobj->Content[n] >= 'A' && stringobj->Content[n-2] >= 'A')) @@ -631,7 +658,8 @@ prt_textlm_FindWrapPoint(pPrtObjStream stringobj, double maxwidth, int* brkpoint } /** Is that all that will fit? **/ - ckw = prt_internal_GetStringWidth(stringobj, (char*)stringobj->Content+n, 1); + n_bytes = prt_textlm_BytesForChar(stringobj->Content+n); + ckw = prt_internal_GetStringWidth(stringobj, (char*)stringobj->Content+n, n_bytes); if (w + ckw > maxwidth) { if (last_sep == -1) @@ -651,6 +679,8 @@ prt_textlm_FindWrapPoint(pPrtObjStream stringobj, double maxwidth, int* brkpoint { w += ckw; } + + n += n_bytes; } /** It all fits. Return most reasonable split pt anyhow **/ diff --git a/centrallix/report/prtmgmt_v3_od_ps.c b/centrallix/report/prtmgmt_v3_od_ps.c index df9bedce2..70d905b10 100644 --- a/centrallix/report/prtmgmt_v3_od_ps.c +++ b/centrallix/report/prtmgmt_v3_od_ps.c @@ -695,9 +695,8 @@ prt_psod_GetCharacterMetric(void* context_v, unsigned char* str, pPrtTextStyle s if (str[0] > 0x7F && CxGlobals.CharacterMode == CharModeUTF8) { /** UTF-8 encoded character, count entire encoded char as one. **/ - str++; n += 1.0; - while ((str[0] & 0xC0) == 0x80) + while ((str[1] & 0xC0) == 0x80) str++; } else if (*str < 0x20 || *str > 0x7E) From dc1610ebc58ecb0b10bb19be1106ade6deab5ecc Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Mon, 22 Jun 2020 09:34:13 -0600 Subject: [PATCH 024/124] End of Sprint 1 --- centrallix/expression/exp_functions.c | 33 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 9f5d04d66..f480caed3 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -3419,7 +3419,10 @@ int exp_fn_utf8_right(pExpression tree, pParamObjects objlist, pExpression i0, p return 0; } -//int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) +/*int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) +{ + return 0; +}*/ int exp_fn_nth(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { @@ -3448,8 +3451,8 @@ int exp_fn_nth(pExpression tree, pParamObjects objlist, pExpression i0, pExpress } -int -exp_internal_DefineFunctions() +//int exp_internal_DefineFunctions() +int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { size_t bufferLength = 64; size_t initialPosition; @@ -3668,6 +3671,8 @@ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, int exp_internal_DefineFunctions() { + + /** Function list for EXPR_N_FUNCTION nodes **/ xhAdd(&EXP.Functions, "getdate", (char*) exp_fn_getdate); xhAdd(&EXP.Functions, "user_name", (char*) exp_fn_user_name); @@ -3685,6 +3690,7 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "eval", (char*) exp_fn_eval); xhAdd(&EXP.Functions, "round", (char*) exp_fn_round); xhAdd(&EXP.Functions, "dateadd", (char*) exp_fn_dateadd); + xhAdd(&EXP.Functions, "datediff", (char*) exp_fn_datediff); xhAdd(&EXP.Functions, "truncate", (char*) exp_fn_truncate); xhAdd(&EXP.Functions, "constrain", (char*) exp_fn_constrain); xhAdd(&EXP.Functions, "sin", (char*) exp_fn_sin); @@ -3698,7 +3704,20 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "square", (char*) exp_fn_square); xhAdd(&EXP.Functions, "degrees", (char*) exp_fn_degrees); xhAdd(&EXP.Functions, "radians", (char*) exp_fn_radians); - + hAdd(&EXP.Functions, "has_endorsement", (char*)exp_fn_has_endorsement); + xhAdd(&EXP.Functions, "rand", (char*)exp_fn_rand); + xhAdd(&EXP.Functions, "nullif", (char*)exp_fn_nullif); + xhAdd(&EXP.Functions, "dateformat", (char*)exp_fn_dateformat); + xhAdd(&EXP.Functions, "hash", (char*)exp_fn_hash); + xhAdd(&EXP.Functions, "hmac", (char*)exp_fn_hmac); + xhAdd(&EXP.Functions, "log10", (char*)exp_fn_log10); + xhAdd(&EXP.Functions, "power", (char*)exp_fn_power); + xhAdd(&EXP.Functions, "pbkdf2", (char*)exp_fn_pbkdf2); + + /** Windowing **/ + xhAdd(&EXP.Functions, "row_number", (char*)exp_fn_row_number); + + /** Aggregate **/ xhAdd(&EXP.Functions, "count", (char*) exp_fn_count); xhAdd(&EXP.Functions, "avg", (char*) exp_fn_avg); xhAdd(&EXP.Functions, "sum", (char*) exp_fn_sum); @@ -3734,7 +3753,11 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "right", (char*) exp_fn_utf8_right); xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); - } + + xhAdd(&EXP.Functions, "reverse", (char*) exp_fn_utf8_reverse); + xhAdd(&EXP.Functions, "replace", (char*) exp_fn_utf8_replace); + xhAdd(&EXP.Functions, "substitute", (char*) exp_fn_utf8_substitute); + } return 0; } From 8a8c99c4f9be3ae934f55c177e3578ba262760bd Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Tue, 23 Jun 2020 12:21:26 -0600 Subject: [PATCH 025/124] Ready to begin new work --- centrallix-lib/src/xstring.c | 20 +-- centrallix/.Makefile.swp | Bin 0 -> 16384 bytes centrallix/Makefile.in | 3 +- centrallix/centrallix.c | 2 +- centrallix/expression/exp_functions.c | 24 ++- centrallix/include/stparse.h | 9 - centrallix/tests/centrallix.conf-test | 1 + centrallix/tests/centrallix.conf-test.in | 1 + centrallix/utility/stparse.c | 210 ++++++++++------------- 9 files changed, 124 insertions(+), 146 deletions(-) create mode 100644 centrallix/.Makefile.swp mode change 100755 => 100644 centrallix/include/stparse.h mode change 100755 => 100644 centrallix/utility/stparse.c diff --git a/centrallix-lib/src/xstring.c b/centrallix-lib/src/xstring.c index 51df377c2..8f3ed6a8c 100644 --- a/centrallix-lib/src/xstring.c +++ b/centrallix-lib/src/xstring.c @@ -160,7 +160,7 @@ xsCheckAlloc(pXString this, int addl_needed) /*** xsConcatenate - adds text data to the end of the existing string, and *** allocs more memory as needed. If 'len' is -1, then the length is - *** calculated using strlen(), otherwise the given length is enforced. + *** calculated using chrCharLength(), otherwise the given length is enforced. ***/ int xsConcatenate(pXString this, char* text, int len) @@ -171,7 +171,7 @@ xsConcatenate(pXString this, char* text, int len) CXSEC_VERIFY(*this); /** Determine length. **/ - if (len == -1) len = strlen(text); + if (len == -1) len = chrCharLength(text); /** Check memory **/ if (xsCheckAlloc(this,len) < 0) @@ -320,7 +320,7 @@ xs_internal_Printf(pXString this, char* fmt, va_list vl) if (!str) str = "(null)"; do_as_string: /* from int handler, below */ - n = strlen(str); + n = chrCharLength(str); /** Need to pad beginning of string with spaces? **/ if (field_width > precision && precision >= 0) @@ -605,7 +605,7 @@ xsFind(pXString this,char* find,int findlen, int offset) CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(findlen==-1) findlen=strlen(find); + if(findlen==-1) findlen = chrCharLength(find); for(;offsetLength;offset++) { if(this->String[offset]==find[0]) @@ -636,7 +636,7 @@ xsFindRev(pXString this,char* find,int findlen, int offset) CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(findlen==-1) findlen=strlen(find); + if(findlen==-1) findlen = chrCharLength(find); offset=this->Length-offset-1; for(;offset>=0;offset--) { @@ -678,8 +678,8 @@ xsSubst(pXString this, int offset, int len, char* rep, int replen) CXSEC_EXIT(XS_FN_KEY); return -1; } - if (len == -1) len = strlen(this->String + offset); - if (replen == -1) replen = strlen(rep); + if (len == -1) len = chrCharLength(this->String + offset); + if (replen == -1) replen = chrCharLength(rep); /** Make sure we have enough room **/ if (len < replen) xsCheckAlloc(this, replen - len); @@ -704,8 +704,8 @@ xsReplace(pXString this, char* find, int findlen, int offset, char* rep, int rep CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(findlen==-1) findlen=strlen(find); - if(replen==-1) replen=strlen(rep); + if(findlen==-1) findlen = chrCharLength(find); + if(replen==-1) replen = chrCharLength(rep); offset=xsFind(this,find,findlen,offset); if(offset < 0) { @@ -743,7 +743,7 @@ xsInsertAfter(pXString this, char* ins, int inslen, int offset) CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(inslen==-1) inslen=strlen(ins); + if(inslen==-1) inslen = chrCharLength(ins); if(xsCheckAlloc(this,inslen)==-1) { CXSEC_EXIT(XS_FN_KEY); diff --git a/centrallix/.Makefile.swp b/centrallix/.Makefile.swp new file mode 100644 index 0000000000000000000000000000000000000000..c47b09aee97e13c6905029861b1fe2b37b721f5e GIT binary patch literal 16384 zcmeHNZEPb)8J?Cxdo69D6$n8Q(!9m0YyMTq6k5uJTp6MZ*1Q+ zlwYX3(qr$=JM+#v&pSJ_@4MStI9pk#x8|1!j#m-#t^8l!_3f+gyX?Ws2=O@&Mez$A zyUyam;zAHP4)c#)qH-Y${DRF5-7W;aQ80SBjujRR=7zp*+g7izuJ5q6WwT4@$V3?f z83QktfosX}#bXPi_4L%u^u`;`yjVq9yNrR1fsBESfsBESfsBESfsBESf&W7WLhnlQ zKG=P^vi&~wkMLg}$^Y}}_>3xl|A_qGN`6k2zfLtw+W$+*x0L(?Bl72zysqRw9+Cf3 z$y-W3uMAG~|3k@-D)|E=a#fuDWej8tWDH~sWDH~sWDH~sWDH~sWDH~sWDL9{8PLsm z*f)uI8Snq^Q!M=EdP05)d;$0@umM~JJbE1=0q|zv7uOQ<6X26T1$h3IgggRxzz#rx zzg|PgGr*sKKLS4kehPdacntV5@M+*vKp(gpxD|LKa5?bns|k4=cnJ6y-~b!IGH?g* zCg4Wk2H@4emB4d{2zeTK3iu)L81OLgAn+dG-N4&`Jdgvf0Qy%E(gW6kr>`XBo4_}K z`++^c0=9v5U>TSNt_S}93fKtz2zUZ`6!;48An;M(Uf=?-0jvWHz#D+q1HXGYA-@G4 z0v-VN03BEdZUd%(Yk+63AmmrTcY&`0p94M!oCiGMEx;0R6L2~3^vekO0q}L;OThg= z2;2>nfd$|w@HhDUS>PkUoxmD!3n1qL=D{H<58gUw`n%1bA6Rai=Q+KHY@I#6dFt(} z^~%|DU0X&08CKgJP%CY+GT!FI6OZyw>4V%$PqGDwoFyO zoeP$i4|sCf4a4-MV>v7(b^5`1J9XW2(pOH4_aIDJdq6uiSSZe{e50PAMrs#;v1*>7-W5H+x%k47XN)0@&ANujYh7-H#>AvoawKupM z;SlpGx;w~7lCA`sebSoCY8QOZ4 zI^2wG7SOP(htzUBn>jEPmn@c-Y8Be%KE)(qzN_1Gg~HQ>lxnqVX}etC?=Ibwe23^i z_Eu6&cxo%TSVlEv2$`lO&!g+Qt9Rm_t9qaLbgr~sMHB5zt+rWj?C&HBE!ztFaR;hK zJQL0Z+-(Z6oCUnqjsimu6E`#0G5IxHC8dR_3IwCIM8ovs^%&A}wz zN|*}5VU=mBMV`2i2VTzQXiE<)gX*qHb#qsD4QA4qPz%!@-|?I(X_b{r5H97QdwMIb z>4bV9RxKyASx+tjJ>BTodrsza=XvzDlDA?>Ux9GA^Eks4jHSEY_#dz^6 zhAhB_V}-29uu8^vRgr~8ajz5lMWYu4MMrnzYQ@ydhuP8?nxhz>yp>GLhgsYQ$8?WT zG{bZU+iUNv)aWuTv@EwE_9ar;&>E#`wYgeqlpvV7R~5XM<{Wy<($b)Uwow~IRB&{$If**)MsKt`iBavyHKefZbBEf2+$!Ux zQY-~ctSxz5h7|X@&+*)Z`9VD!J4A5v&6Jj0b6yQkJeg733c`8XVm9BycveRE0& zX^;=HvjNPrLQA);3(`WRDPEeSx!95Ay)iFGXN3X9S}A)HgMoD4W=}CwExl#4*+8kP zv}vD5v+#u_oMQ!XW1I6GEY5P1@AAEbJ)L5G77t5<vkiBb} z(6wiU-B?G!+ufv8YKZZnAZR0X}O9f=c?3JI;Cw^&os)_ zZMw0kG>N!E%n{y})~s!up=-4&^`aJB+Jzmhz7(9s12xqWOHOl)QMwKe3YDsO*onf$ zeJYvD@R>TT3AF~T#;nX!JZtH0pW2vQ$?;u=!yiJ2D0`1~LXR1~LXR23`UTsCbg*P39p>gaCe3o*r9bDzJ*e_(swtvMnzQW|9=+pEhslltPMfx=i`;h+ z&-zIcWLOTvrpGKhsco#+n(=r~9?+z?O|^1LLkl_f=|N_ufCxjr3~-UU6_!kvOeD!R zF}nYP@iEolWoL4yQZljA*fYt5Ibiq7CswPF&llj7Tb8I|V$3G>c47h%Qu4w!3H^9W zv3O8wCfJsh>AWg7078zJ=WLzxb?Km5cAPccB@&gE9TZrNN z$Rpx~)gB`1Bs@2|%-E4RkwJw*6M_nAF980O;{`#sB~S literal 0 HcmV?d00001 diff --git a/centrallix/Makefile.in b/centrallix/Makefile.in index ba2e23680..fe0399df9 100755 --- a/centrallix/Makefile.in +++ b/centrallix/Makefile.in @@ -76,9 +76,8 @@ XSUPPORT=stparse.o \ mime/mime_util.o \ ptod.o \ iface.o \ - charsets.o + charsets.o \ param.o \ - iface.o \ endorsement_utils.o \ obfuscate.o \ json_util.o diff --git a/centrallix/centrallix.c b/centrallix/centrallix.c index 262b6b4ce..eb5b8cc61 100755 --- a/centrallix/centrallix.c +++ b/centrallix/centrallix.c @@ -398,7 +398,7 @@ cxInitialize(void* v) thisCharsetPtr = stLookup(CxGlobals.CharsetMap, nl_langinfo(CODESET)); if(thisCharsetPtr) { - stSeparate(thisCharsetPtr); + stLinkInf(thisCharsetPtr); stFreeInf(CxGlobals.CharsetMap); CxGlobals.CharsetMap = thisCharsetPtr; } diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index f480caed3..4da4eb07f 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -3450,8 +3450,6 @@ int exp_fn_nth(pExpression tree, pParamObjects objlist, pExpression i0, pExpress return 0; } - -//int exp_internal_DefineFunctions() int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { size_t bufferLength = 64; @@ -3668,6 +3666,21 @@ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, } } +int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + return 0; + } + +int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + return 0; + } + +int exp_fn_utf8_substitute(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) + { + return 0; + } + int exp_internal_DefineFunctions() { @@ -3704,7 +3717,7 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "square", (char*) exp_fn_square); xhAdd(&EXP.Functions, "degrees", (char*) exp_fn_degrees); xhAdd(&EXP.Functions, "radians", (char*) exp_fn_radians); - hAdd(&EXP.Functions, "has_endorsement", (char*)exp_fn_has_endorsement); + xhAdd(&EXP.Functions, "has_endorsement", (char*)exp_fn_has_endorsement); xhAdd(&EXP.Functions, "rand", (char*)exp_fn_rand); xhAdd(&EXP.Functions, "nullif", (char*)exp_fn_nullif); xhAdd(&EXP.Functions, "dateformat", (char*)exp_fn_dateformat); @@ -3741,7 +3754,10 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "right", (char*) exp_fn_right); xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_escape); - } + xhAdd(&EXP.Functions, "reverse", (char*) exp_fn_reverse); + xhAdd(&EXP.Functions, "replace", (char*) exp_fn_replace); + xhAdd(&EXP.Functions, "substitute", (char*) exp_fn_substitute); + } else { xhAdd(&EXP.Functions, "substring", (char*) exp_fn_utf8_substring); diff --git a/centrallix/include/stparse.h b/centrallix/include/stparse.h old mode 100755 new mode 100644 index 79dcf15e2..c7e16cf37 --- a/centrallix/include/stparse.h +++ b/centrallix/include/stparse.h @@ -131,14 +131,5 @@ int stSetAttrValue(pStructInf this, int type, pObjData value, int nval); pExpression stGetExpression(pStructInf this, int nval); void* stGetValueList(pStructInf this, int type, unsigned int* nval); int stAttrIsList(pStructInf this); -/** \brief Separate a subtree from its parent. - - After calling this, you are responsible to free both this subtree - and its parent if there is one. - \param toSeparate The tree to separate from its parent, i f it has one. - \return This returns 0 in all cases. - */ -int stSeparate(pStructInf toSeparate); #endif /* _STPARSE_H */ - diff --git a/centrallix/tests/centrallix.conf-test b/centrallix/tests/centrallix.conf-test index a3c48a3aa..7ec912e78 100644 --- a/centrallix/tests/centrallix.conf-test +++ b/centrallix/tests/centrallix.conf-test @@ -14,6 +14,7 @@ centrallix "system/config" iface_dir = "/sys/ifc"; // this is an OSML path theme_dir = "/sys/themes"; // OSML path transaction_log_file = "/var/log/cx_transaction_log"; + charsetmap_file = "/usr/local/src/cx-git/centrallix/etc/charsetmap.cfg"; // Set this to 1 to allow Centrallix to send a user's login credentials // to another server, as a part of "single sign on" type authentication. diff --git a/centrallix/tests/centrallix.conf-test.in b/centrallix/tests/centrallix.conf-test.in index 635752eab..2e45dc990 100644 --- a/centrallix/tests/centrallix.conf-test.in +++ b/centrallix/tests/centrallix.conf-test.in @@ -14,6 +14,7 @@ centrallix "system/config" iface_dir = "/sys/ifc"; // this is an OSML path theme_dir = "/sys/themes"; // OSML path transaction_log_file = "/var/log/cx_transaction_log"; + charsetmap_file = "/usr/local/src/cx-git/centrallix/etc/charsetmap.cfg"; //hardcoded path // Set this to 1 to allow Centrallix to send a user's login credentials // to another server, as a part of "single sign on" type authentication. diff --git a/centrallix/utility/stparse.c b/centrallix/utility/stparse.c old mode 100755 new mode 100644 index ae9ef80b1..6aaeea596 --- a/centrallix/utility/stparse.c +++ b/centrallix/utility/stparse.c @@ -54,7 +54,7 @@ int st_internal_GenerateAttr(pStructInf info, pXString xs, int level, pParamObje /*** stPrintInf - print a struct inf tree - ***/ + * ***/ int stPrintInf(pStructInf this) { @@ -71,7 +71,7 @@ stPrintInf(pStructInf this) /*** stAllocInf - allocate a new StructInf structure. - ***/ + * ***/ pStructInf stAllocInf() { @@ -90,7 +90,7 @@ stAllocInf() /*** stLinkInf - add a reference count to a structinf - ***/ + * ***/ pStructInf stLinkInf(pStructInf this) { @@ -103,31 +103,9 @@ stLinkInf(pStructInf this) return this; } -int stSeparate(pStructInf this){ - int i,j; - - /** Disconnect from parent if there is one. **/ - if (this->Parent) - { - ASSERTMAGIC(this->Parent,MGK_STRUCTINF); - for(i=0;iParent->nSubInf;i++) - { - if (this == this->Parent->SubInf[i]) - { - this->Parent->nSubInf--; - for(j=i;jParent->nSubInf;j++) - { - this->Parent->SubInf[j] = this->Parent->SubInf[j+1]; - } - this->Parent->SubInf[this->Parent->nSubInf] = NULL; - } - } - } - return 0; -} /*** stFreeInf - release an existing StructInf, and any sub infs - ***/ + * ***/ int stFreeInf_r(pStructInf this, int parentcnt) { @@ -161,9 +139,9 @@ stFreeInf_r(pStructInf this, int parentcnt) this->Parent->nSubInf--; memmove(this->Parent->SubInf+i, this->Parent->SubInf+i+1, (this->Parent->nSubInf - i) * sizeof(pStructInf)); /*for(j=i;jParent->nSubInf;j++) - { - this->Parent->SubInf[j] = this->Parent->SubInf[j+1]; - }*/ + * { + * this->Parent->SubInf[j] = this->Parent->SubInf[j+1]; + * }*/ this->Parent->SubInf[this->Parent->nSubInf] = NULL; break; } @@ -209,7 +187,7 @@ stTestAndFreeInf(pStructInf this) int stFreeInf(pStructInf this) { -// int i; + ASSERTMAGIC(this,MGK_STRUCTINF); this->LinkCnt--; @@ -221,17 +199,9 @@ stFreeInf(pStructInf this) } - -// /** Disconnect from parent if there is one. **/ -// stSeparate(this); -// -// /** Free the current one. **/ -// nmFree(this,sizeof(StructInf)); - - /*** stRemoveInf - removes a node from its parent, freeing it if that causes it - *** to have a zero reference count. - ***/ + * *** to have a zero reference count. + * ***/ int stRemoveInf(pStructInf this) { @@ -262,11 +232,11 @@ stRemoveInf(pStructInf this) /*** stAddInf - add a subinf to the main inf structure. Reference counting note: - *** since subinf's "automatically" inherit their parent's reference count, we - *** subtract one when adding it to the parent. The assumption is that the caller - *** holds a ref to both the inf and subinf, and so we combine those into one once - *** the subinf is added. - ***/ + * *** since subinf's "automatically" inherit their parent's reference count, we + * *** subtract one when adding it to the parent. The assumption is that the caller + * *** holds a ref to both the inf and subinf, and so we combine those into one once + * *** the subinf is added. + * ***/ int stAddInf(pStructInf main_inf, pStructInf sub_inf) { @@ -303,9 +273,9 @@ stAddInf(pStructInf main_inf, pStructInf sub_inf) /*** stAddAttr - adds an attribute to the existing inf. Reference counting - *** note: the new attribute by default will have the same reference count as - *** the node it was added to. - ***/ + * *** note: the new attribute by default will have the same reference count as + * *** the node it was added to. + * ***/ pStructInf stAddAttr(pStructInf inf, char* name) { @@ -328,7 +298,7 @@ stAddAttr(pStructInf inf, char* name) /*** stAddGroup - adds a subgroup to an existing inf. - ***/ + * ***/ pStructInf stAddGroup(pStructInf inf, char* name, char* type) { @@ -354,7 +324,7 @@ stAddGroup(pStructInf inf, char* name, char* type) /*** stAddValue - adds a value to the attribute inf. - ***/ + * ***/ int stAddValue(pStructInf inf, char* strval, int intval) { @@ -416,7 +386,7 @@ stAddValue(pStructInf inf, char* strval, int intval) /*** stCreateStruct - creates a new command inf. - ***/ + * ***/ pStructInf stCreateStruct(char* name, char* type) { @@ -446,8 +416,8 @@ stCreateStruct(char* name, char* type) /*** stLookup - find an attribute or subgroup in the protoinf and - *** return the attribute inf. - ***/ + * *** return the attribute inf. + * ***/ pStructInf stLookup(pStructInf this, char* name) { @@ -472,7 +442,7 @@ stLookup(pStructInf this, char* name) /*** stAttrValue - return the value of an attribute inf. - ***/ + * ***/ int stAttrValue(pStructInf this, int* intval, char** strval, int nval) { @@ -511,8 +481,8 @@ stAttrValue(pStructInf this, int* intval, char** strval, int nval) /*** stGetExpression - returns the appropriate expression element that - *** represents the th element. - ***/ + * *** represents the th element. + * ***/ pExpression stGetExpression(pStructInf this, int nval) { @@ -545,8 +515,8 @@ stGetExpression(pStructInf this, int nval) /*** stGetAttrValue - returns the value of an expression in a - *** structure file. - ***/ + * *** structure file. + * ***/ int stGetAttrValue(pStructInf this, int type, pObjData pod, int nval) { @@ -555,9 +525,9 @@ stGetAttrValue(pStructInf this, int type, pObjData pod, int nval) /*** stGetObjAttrValue - return the value of an expression in a structure - *** file, given the struct node containing the attribute. This call is - *** designed to have the same API as objGetAttrValue(). - ***/ + * *** file, given the struct node containing the attribute. This call is + * *** designed to have the same API as objGetAttrValue(). + * ***/ int stGetObjAttrValue(pStructInf this, char* attrname, int type, pObjData value) { @@ -576,8 +546,8 @@ stGetObjAttrValue(pStructInf this, char* attrname, int type, pObjData value) /*** stGetAttrValueOSML - return the value of an expression, evaluated - *** in the context of an OSML session. - ***/ + * *** in the context of an OSML session. + * ***/ int stGetAttrValueOSML(pStructInf this, int type, pObjData pod, int nval, pObjSession sess) { @@ -618,7 +588,7 @@ stGetAttrValueOSML(pStructInf this, int type, pObjData pod, int nval, pObjSessio /*** stGetAttrType - return the data type of an expression. - ***/ + * ***/ int stGetAttrType(pStructInf this, int nval) { @@ -641,8 +611,8 @@ stGetAttrType(pStructInf this, int nval) /*** stStructType - return the type of structure, either attribute - *** or group (as ST_T_xxxx). - ***/ + * *** or group (as ST_T_xxxx). + * ***/ int stStructType(pStructInf this) { @@ -654,7 +624,7 @@ stStructType(pStructInf this) /*** stSetAttrValue - sets the nth value of an attribute. - ***/ + * ***/ int stSetAttrValue(pStructInf inf, int type, pObjData value, int nval) { @@ -705,9 +675,9 @@ stSetAttrValue(pStructInf inf, int type, pObjData value, int nval) /*** stGetValueList - return a list of values as a nmSysMalloc'd array - *** but only return those that match the given data type, unless the - *** type is DATA_T_ANY. - ***/ + * *** but only return those that match the given data type, unless the + * *** type is DATA_T_ANY. + * ***/ void* stGetValueList(pStructInf this, int type, unsigned int* nval) { @@ -768,8 +738,8 @@ stGetValueList(pStructInf this, int type, unsigned int* nval) /*** stAttrIsList - returns nonzero if the attribute inf is a EXPR_N_LIST value - *** type, and 0 if it is a scalar. - ***/ + * *** type, and 0 if it is a scalar. + * ***/ int stAttrIsList(pStructInf this) { @@ -778,9 +748,9 @@ stAttrIsList(pStructInf this) /*** st_internal_ParseAttr - parse an attribute. This routine - *** should be called with the current token set at the equals - *** sign. - ***/ + * *** should be called with the current token set at the equals + * *** sign. + * ***/ int st_internal_ParseAttr(pLxSession s, pStructInf inf, pParamObjects objlist) { @@ -884,9 +854,9 @@ st_internal_ParseAttr(pLxSession s, pStructInf inf, pParamObjects objlist) /*** st_internal_ParseGroup - parse a subgroup within a command - *** or another subgroup. Should be called with the current - *** token set to the open brace. - ***/ + * *** or another subgroup. Should be called with the current + * *** token set to the open brace. + * ***/ int st_internal_ParseGroup(pLxSession s, pStructInf inf, pParamObjects objlist) { @@ -1005,8 +975,8 @@ st_internal_ParseGroup(pLxSession s, pStructInf inf, pParamObjects objlist) /*** st_internal_IsDblOpen - check a string to see if it is a double-open- - *** brace on a line by itself with only surrounding whitespace. - ***/ + * *** brace on a line by itself with only surrounding whitespace. + * ***/ int st_internal_IsDblOpen(char* str) { @@ -1028,8 +998,8 @@ st_internal_IsDblOpen(char* str) /*** st_internal_IsDblClose - check a string to see if it is a double-close- - *** brace on a line by itself. - ***/ + * *** brace on a line by itself. + * ***/ int st_internal_IsDblClose(char* str) { @@ -1051,10 +1021,10 @@ st_internal_IsDblClose(char* str) /*** st_internal_ParseScript - parse an embedded JavaScript segment within - *** a structure file. This is called once a {{ has been encountered - *** during group processing, and this routine will continue until a - *** matching }} is encountered. - ***/ + * *** a structure file. This is called once a {{ has been encountered + * *** during group processing, and this routine will continue until a + * *** matching }} is encountered. + * ***/ int st_internal_ParseScript(pLxSession s, pStructInf info) { @@ -1092,8 +1062,8 @@ st_internal_ParseScript(pLxSession s, pStructInf info) /** Breaking out of script and into structure file again? **/ /*if (st_internal_IsDblOpen(str)) - { - }*/ + * { + * }*/ } /** build the structinf entry **/ @@ -1110,8 +1080,8 @@ st_internal_ParseScript(pLxSession s, pStructInf info) /*** st_internal_ParseStruct - parse a command structure from the - *** input stream. - ***/ + * *** input stream. + * ***/ int st_internal_ParseStruct(pLxSession s, pStructInf *info) { @@ -1181,9 +1151,9 @@ st_internal_ParseStruct(pLxSession s, pStructInf *info) /** GRB 2/2000 - Is this a FormLayout style file? **/ /*if (!strcmp((*info)->Name, "BEGIN")) - { - return st_internal_FLStruct(s, *info); - }*/ + * { + * return st_internal_FLStruct(s, *info); + * }*/ /** If a subgroup, will have a type. Check for it. **/ toktype = mlxNextToken(s); @@ -1215,8 +1185,8 @@ st_internal_ParseStruct(pLxSession s, pStructInf *info) /*** stParseMsg - parse an incoming message from a file or network - *** connection. - ***/ + * *** connection. + * ***/ pStructInf stParseMsg(pFile inp_fd, int flags) { @@ -1242,8 +1212,8 @@ stParseMsg(pFile inp_fd, int flags) /*** stParseMsgGeneric - parse an incoming message from a generic - *** descriptor via a read-function. - ***/ + * *** descriptor via a read-function. + * ***/ pStructInf stParseMsgGeneric(void* src, int (*read_fn)(), int flags) { @@ -1269,8 +1239,8 @@ stParseMsgGeneric(void* src, int (*read_fn)(), int flags) /*** stProbeTypeGeneric() - read just enough of a structure file to figure - *** out the type of the top level group. - ***/ + * *** out the type of the top level group. + * ***/ int stProbeTypeGeneric(void* read_src, int (*read_fn)(), char* type, int type_maxlen) { @@ -1327,8 +1297,8 @@ stProbeTypeGeneric(void* read_src, int (*read_fn)(), char* type, int type_maxlen /*** st_internal_CkAddBuf - check to see if we need to realloc on the buffer - *** to add n characters. - ***/ + * *** to add n characters. + * ***/ int st_internal_CkAddBuf(char** buf, int* buflen, int* datalen, int n) { @@ -1349,8 +1319,8 @@ st_internal_CkAddBuf(char** buf, int* buflen, int* datalen, int n) /*** st_internal_GenerateGroup - output a group listing from an info - *** structure. - ***/ + * *** structure. + * ***/ int st_internal_GenerateGroup(pStructInf info, pXString xs, int level, pParamObjects objlist) { @@ -1376,8 +1346,8 @@ st_internal_GenerateGroup(pStructInf info, pXString xs, int level, pParamObjects /*** st_internal_GenerateAttr - output a single attribute from an - *** info structure. - ***/ + * *** info structure. + * ***/ int st_internal_GenerateAttr(pStructInf info, pXString xs, int level, pParamObjects objlist) { @@ -1413,8 +1383,8 @@ st_internal_GenerateAttr(pStructInf info, pXString xs, int level, pParamObjects /*** stGenerateMsg - generate a message to output to a file or network - *** connection. - ***/ + * *** connection. + * ***/ int stGenerateMsgGeneric(void* dst, int (*write_fn)(), pStructInf info, int flags) { @@ -1467,7 +1437,7 @@ stGenerateMsg(pFile fd, pStructInf info, int flags) #if 00 /*** st_internal_FLStruct - parse a FormLayout structure file. - ***/ + * ***/ int st_internal_FLStruct(pLxSession s, pStructInf info) { @@ -1556,8 +1526,8 @@ st_internal_FLStruct(pLxSession s, pStructInf info) /*** stCreateStruct_ne - uses the simplified one-string-value-only - *** ne version of the structures. Create a new top-level structure. - ***/ + * *** ne version of the structures. Create a new top-level structure. + * ***/ pStruct stCreateStruct_ne(char* name) { @@ -1577,7 +1547,7 @@ stCreateStruct_ne(char* name) /*** stAddAttr_ne - Add an attribute to a struct inf - ***/ + * ***/ pStruct stAddAttr_ne(pStruct this, char* name) { @@ -1596,7 +1566,7 @@ stAddAttr_ne(pStruct this, char* name) /*** stAddGroup_ne - add a subgroup to a group. - ***/ + * ***/ pStruct stAddGroup_ne(pStruct this, char* name) { @@ -1615,7 +1585,7 @@ stAddGroup_ne(pStruct this, char* name) /*** stAddValue_ne - set the string value of a group. - ***/ + * ***/ int stAddValue_ne(pStruct this, char* strval) { @@ -1630,7 +1600,7 @@ stAddValue_ne(pStruct this, char* strval) /*** stLookup_ne - lookup a subinf in an inf. - ***/ + * ***/ pStruct stLookup_ne(pStruct this, char* name) { @@ -1649,7 +1619,7 @@ stLookup_ne(pStruct this, char* name) /*** stAttrValue_ne - get the value of an attribute. - ***/ + * ***/ int stAttrValue_ne(pStruct this, char** strval) { @@ -1665,7 +1635,7 @@ stAttrValue_ne(pStruct this, char** strval) /*** stAllocInf_ne - allocate an inf. - ***/ + * ***/ pStruct stAllocInf_ne() { @@ -1680,7 +1650,7 @@ stAllocInf_ne() /*** stFreeInf_ne_r - recursively deallocate an inf tree - ***/ + * ***/ int stFreeInf_ne_r(pStruct this) { @@ -1701,7 +1671,7 @@ stFreeInf_ne_r(pStruct this) /*** stFreeInf_ne - deallocate an inf. - ***/ + * ***/ int stFreeInf_ne(pStruct this) { @@ -1732,7 +1702,7 @@ stFreeInf_ne(pStruct this) /*** stAddInf_ne - add a subinf to a parent inf. - ***/ + * ***/ int stAddInf_ne(pStruct main_inf, pStruct sub_inf) { @@ -1744,7 +1714,7 @@ stAddInf_ne(pStruct main_inf, pStruct sub_inf) /*** stPrint_ne - format and print a pStruct tree on stdout. - ***/ + * ***/ int stPrint_ne_r(pStruct inf, int level) { From e3bdb3f5cfdbca38c77cd185659026443b501afb Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Wed, 24 Jun 2020 08:47:51 -0600 Subject: [PATCH 026/124] Pre SQL merge --- centrallix-lib/src/xstring.c | 6 +- centrallix/expression/exp_functions.c | 147 +++++++++++++------------- centrallix/tests/centrallix.conf-test | 2 +- 3 files changed, 80 insertions(+), 75 deletions(-) diff --git a/centrallix-lib/src/xstring.c b/centrallix-lib/src/xstring.c index 8f3ed6a8c..ee5412aa7 100644 --- a/centrallix-lib/src/xstring.c +++ b/centrallix-lib/src/xstring.c @@ -160,7 +160,7 @@ xsCheckAlloc(pXString this, int addl_needed) /*** xsConcatenate - adds text data to the end of the existing string, and *** allocs more memory as needed. If 'len' is -1, then the length is - *** calculated using chrCharLength(), otherwise the given length is enforced. + *** calculated using strlen(), otherwise the given length is enforced. ***/ int xsConcatenate(pXString this, char* text, int len) @@ -171,7 +171,7 @@ xsConcatenate(pXString this, char* text, int len) CXSEC_VERIFY(*this); /** Determine length. **/ - if (len == -1) len = chrCharLength(text); + if (len == -1) len = strlen(text); /** Check memory **/ if (xsCheckAlloc(this,len) < 0) @@ -605,7 +605,7 @@ xsFind(pXString this,char* find,int findlen, int offset) CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(findlen==-1) findlen = chrCharLength(find); + if(findlen==-1) findlen = strlen(find); for(;offsetLength;offset++) { if(this->String[offset]==find[0]) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 4da4eb07f..54ecf2548 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -3541,76 +3541,7 @@ int exp_fn_utf8_ralign(pExpression tree, pParamObjects objlist, pExpression i0, return -1; } } - - /** Function list for EXPR_N_FUNCTION nodes ** - xhAdd(&EXP.Functions, "getdate", (char*)exp_fn_getdate); - xhAdd(&EXP.Functions, "user_name", (char*)exp_fn_user_name); - xhAdd(&EXP.Functions, "convert", (char*)exp_fn_convert); - xhAdd(&EXP.Functions, "wordify", (char*)exp_fn_wordify); - xhAdd(&EXP.Functions, "abs", (char*)exp_fn_abs); - xhAdd(&EXP.Functions, "ascii", (char*)exp_fn_ascii); - xhAdd(&EXP.Functions, "condition", (char*)exp_fn_condition); - xhAdd(&EXP.Functions, "charindex", (char*)exp_fn_charindex); - xhAdd(&EXP.Functions, "upper", (char*)exp_fn_upper); - xhAdd(&EXP.Functions, "lower", (char*)exp_fn_lower); - xhAdd(&EXP.Functions, "char_length", (char*)exp_fn_char_length); - xhAdd(&EXP.Functions, "datepart", (char*)exp_fn_datepart); - xhAdd(&EXP.Functions, "isnull", (char*)exp_fn_isnull); - xhAdd(&EXP.Functions, "ltrim", (char*)exp_fn_ltrim); - xhAdd(&EXP.Functions, "lztrim", (char*)exp_fn_lztrim); - xhAdd(&EXP.Functions, "rtrim", (char*)exp_fn_rtrim); - xhAdd(&EXP.Functions, "substring", (char*)exp_fn_substring); - xhAdd(&EXP.Functions, "right", (char*)exp_fn_right); - xhAdd(&EXP.Functions, "ralign", (char*)exp_fn_ralign); - xhAdd(&EXP.Functions, "replicate", (char*)exp_fn_replicate); - xhAdd(&EXP.Functions, "reverse", (char*)exp_fn_reverse); - xhAdd(&EXP.Functions, "replace", (char*)exp_fn_replace); - xhAdd(&EXP.Functions, "escape", (char*)exp_fn_escape); - xhAdd(&EXP.Functions, "quote", (char*)exp_fn_quote); - xhAdd(&EXP.Functions, "substitute", (char*)exp_fn_substitute); - xhAdd(&EXP.Functions, "eval", (char*)exp_fn_eval); - xhAdd(&EXP.Functions, "round", (char*)exp_fn_round); - xhAdd(&EXP.Functions, "dateadd", (char*)exp_fn_dateadd); - xhAdd(&EXP.Functions, "datediff", (char*)exp_fn_datediff); - xhAdd(&EXP.Functions, "truncate", (char*)exp_fn_truncate); - xhAdd(&EXP.Functions, "constrain", (char*)exp_fn_constrain); - xhAdd(&EXP.Functions, "sin", (char*)exp_fn_sin); - xhAdd(&EXP.Functions, "cos", (char*)exp_fn_cos); - xhAdd(&EXP.Functions, "tan", (char*)exp_fn_tan); - xhAdd(&EXP.Functions, "asin", (char*)exp_fn_asin); - xhAdd(&EXP.Functions, "acos", (char*)exp_fn_acos); - xhAdd(&EXP.Functions, "atan", (char*)exp_fn_atan); - xhAdd(&EXP.Functions, "atan2", (char*)exp_fn_atan2); - xhAdd(&EXP.Functions, "sqrt", (char*)exp_fn_sqrt); - xhAdd(&EXP.Functions, "square", (char*)exp_fn_square); - xhAdd(&EXP.Functions, "degrees", (char*)exp_fn_degrees); - xhAdd(&EXP.Functions, "radians", (char*)exp_fn_radians); - xhAdd(&EXP.Functions, "has_endorsement", (char*)exp_fn_has_endorsement); - xhAdd(&EXP.Functions, "rand", (char*)exp_fn_rand); - xhAdd(&EXP.Functions, "nullif", (char*)exp_fn_nullif); - xhAdd(&EXP.Functions, "dateformat", (char*)exp_fn_dateformat); - xhAdd(&EXP.Functions, "hash", (char*)exp_fn_hash); - xhAdd(&EXP.Functions, "hmac", (char*)exp_fn_hmac); - xhAdd(&EXP.Functions, "log10", (char*)exp_fn_log10); - xhAdd(&EXP.Functions, "power", (char*)exp_fn_power); - xhAdd(&EXP.Functions, "pbkdf2", (char*)exp_fn_pbkdf2); - - ** Windowing ** - xhAdd(&EXP.Functions, "row_number", (char*)exp_fn_row_number); - - ** Aggregate ** - xhAdd(&EXP.Functions, "count", (char*)exp_fn_count); - xhAdd(&EXP.Functions, "avg", (char*)exp_fn_avg); - xhAdd(&EXP.Functions, "sum", (char*)exp_fn_sum); - xhAdd(&EXP.Functions, "max", (char*)exp_fn_max); - xhAdd(&EXP.Functions, "min", (char*)exp_fn_min); - xhAdd(&EXP.Functions, "first", (char*)exp_fn_first); - xhAdd(&EXP.Functions, "last", (char*)exp_fn_last); - xhAdd(&EXP.Functions, "nth", (char*)exp_fn_nth); - - ** Reverse functions ** - xhAdd(&EXP.ReverseFunctions, "isnull", (char*)exp_fn_reverse_isnull);*/ - + /** escape(string, escchars, badchars) **/ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { @@ -3668,7 +3599,81 @@ int exp_fn_utf8_escape(pExpression tree, pParamObjects objlist, pExpression i0, int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - return 0; + int charLen, byteLen, a, i, end; + char* temp; + char ch1, ch2, ch3, ch4; + char mask1 = 0x80, mask2 = 0xC0, mask3 = 0xE0, mask4 = 0xF0; + if (i0 && (i0->Flags & EXPR_F_NULL)) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING) + { + mssError(1,"EXP","reverse() expects one string parameter"); + return -1; + } + if (tree->Alloc && tree->String) + nmSysFree(tree->String); + tree->DataType = DATA_T_STRING; + byteLen = strlen(i0->String); + if (byteLen >= 64) + { + tree->String = nmSysMalloc(byteLen+1); + tree->Alloc = 1; + } + else + { + tree->Alloc = 0; + tree->String = tree->Types.StringBuf; + } + strcpy(tree->String, i0->String); + + /** Reversing string **/ + i = 0; + end = byteLen-1; + temp = (char*)nmSysMalloc(sizeof(char) * byteLen+1); + temp[byteLen] = '\0'; + charLen = chrCharLength(i0->String); + for(a = 0; a < charLen; a++) + { + ch1 = tree->String[i]; + if ((ch1 & mask1) == 0x00) + { + temp[end--] = ch1; + i++; + } + else if ((ch1 & mask2) == 0xC0) + { + ch2 = tree->String[++i]; + temp[end--] = ch2; + temp[end--] = ch1; + i++; + } + else if ((ch1 & mask3) == 0xE0) + { + ch2 = tree->String[++i]; + ch3 = tree->String[++i]; + temp[end--] = ch3; + temp[end--] = ch2; + temp[end--] = ch1; + i++; + } + else if ((ch1 & mask4) == 0xF0) + { + ch2 = tree->String[++i]; + ch3 = tree->String[++i]; + ch4 = tree->String[++i]; + temp[end--] = ch4; + temp[end--] = ch3; + temp[end--] = ch2; + temp[end--] = ch1; + i++; } + } + strcpy(tree->String, temp); + + return 0; } int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) diff --git a/centrallix/tests/centrallix.conf-test b/centrallix/tests/centrallix.conf-test index 7ec912e78..9f56242fa 100644 --- a/centrallix/tests/centrallix.conf-test +++ b/centrallix/tests/centrallix.conf-test @@ -14,7 +14,7 @@ centrallix "system/config" iface_dir = "/sys/ifc"; // this is an OSML path theme_dir = "/sys/themes"; // OSML path transaction_log_file = "/var/log/cx_transaction_log"; - charsetmap_file = "/usr/local/src/cx-git/centrallix/etc/charsetmap.cfg"; + charsetmap_file = "/usr/local/src/cx-git/centrallix/etc/charsetmap.cfg"; //hardcoded path // Set this to 1 to allow Centrallix to send a user's login credentials // to another server, as a part of "single sign on" type authentication. From 64acf630f57ce8898359d36fab3239fdce614cba Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Fri, 26 Jun 2020 08:51:39 -0600 Subject: [PATCH 027/124] No Overlong --- centrallix/expression/exp_functions.c | 37 +++++++++++++++++++---- centrallix/include/charsets.h | 6 ++++ centrallix/utility/charsets.c | 43 +++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 54ecf2548..fe5b4b3f2 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -758,7 +758,7 @@ int exp_fn_replicate(pExpression tree, pParamObjects objlist, pExpression i0, pE return 0; } - +//i0 is haystack, i1 is needle, i2 is replacement int exp_fn_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { char* repstr; @@ -797,7 +797,7 @@ int exp_fn_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExp replen = strlen(repstr); searchlen = strlen(i1->String); if (replen > searchlen) - newsize = (newsize * replen) / searchlen + 1; + newsize = (newsize * replen) / searchlen + 1;//why * and / instead of + and - if (newsize >= 0x7FFFFFFFLL) { mssError(1,"EXP","replace(): out of memory"); @@ -3639,7 +3639,7 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, for(a = 0; a < charLen; a++) { ch1 = tree->String[i]; - if ((ch1 & mask1) == 0x00) + if ((ch1 & mask1) == 0x00)//maybe add helper functions instead of masks and validate following continuation bytes { temp[end--] = ch1; i++; @@ -3677,8 +3677,32 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, } int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - return 0; + { + char* repstr; + long long newsize; + char* srcptr; + char* searchptr; + char* dstptr; + int searchlen, replen; + if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) + { tree->Flags |= EXPR_F_NULL; tree->DataType = DATA_T_STRING; + return 0; + } + if (!i0 || i0->DataType != DATA_T_STRING || !i1 || i1->DataType != DATA_T_STRING || !i2 || (!(i2->Flags & EXPR_F_NULL) && i2->DataType != DATA_T_STRING)) + { mssError(1,"EXP","replace() expects three string parameters (str,search,replace)"); + return -1; + } + if (i2->Flags & EXPR_F_NULL) + repstr = ""; + else + repstr = i2->String; + + if (tree->Alloc && tree->String) + nmSysFree(tree->String); + tree->Alloc = 0; + if (i1->String[0] == '\0') { tree->String = i0->String; + return 0; + } } int exp_fn_utf8_substitute(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) @@ -3743,7 +3767,8 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "min", (char*) exp_fn_min); xhAdd(&EXP.Functions, "first", (char*) exp_fn_first); xhAdd(&EXP.Functions, "last", (char*) exp_fn_last); - + xhAdd(&EXP.Functions, "nth", (char*) exp_fn_nth); + /** Reverse functions **/ xhAdd(&EXP.ReverseFunctions, "isnull", (char*) exp_fn_reverse_isnull); diff --git a/centrallix/include/charsets.h b/centrallix/include/charsets.h index a258c7df3..bf4d4fa06 100755 --- a/centrallix/include/charsets.h +++ b/centrallix/include/charsets.h @@ -163,6 +163,12 @@ char* chrToLower(char* string, char* buffer, size_t* bufferLength); CHR_INVALID_CHAR on error. */ size_t chrCharLength(char* string); +/** \brief This function ensures that a multibyte string will be in simplest form. + \param string The string to simplify. + \return This returns the same string but with the minimum amount of bytes used + or NULL on error. */ +char* charNoOverlong(char* string); + /** \brief Get a specific number of the rightmost characters in the string. This function always returns an offset into the original string since no diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c index 527c87186..578053351 100755 --- a/centrallix/utility/charsets.c +++ b/centrallix/utility/charsets.c @@ -322,6 +322,49 @@ size_t chrCharLength(char* string) return length; } +char* charNoOverlong(char* string) + { + size_t stringCharLength, newStrByteLength; + char* toReturn; + wchar_t* longBuffer; + + /** Check arguments **/ + if(!string) + return CHR_INVALID_ARGUMENT; + + stringCharLength = mbstowcs(NULL, string, 0); + if(stringCharLength == (size_t)-1) + { + return NULL; + } + + /** Create wchar_t buffer */ + longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); + if(!longBuffer) + return NULL; + mbstowcs(longBuffer, string, stringCharLength + 1); + + /** Convert back to MBS **/ + newStrByteLength = wcstombs(NULL, longBuffer, 0); + if(newStrByteLength == (size_t)-1) + { + nmSysFree(longBuffer); + return NULL; + } + + toReturn = (char *)nmSysMalloc(newStrByteLength + 1); + if(!toReturn) + { + nmSysFree(longBuffer); + return NULL; + } + + wcstombs(toReturn, longBuffer, newStrByteLength + 1); + nmSysFree(longBuffer); + nmSysFree(string); //good? + return toReturn; + } + char* chrRight(char* string, size_t offsetFromEnd, size_t* returnCode) { size_t currentPos = 0, numScanned = 0; From cd3d0a29615465fef280849d222e07f0a05778be Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Wed, 1 Jul 2020 12:36:01 -0600 Subject: [PATCH 028/124] Foreign Lang Tests Started --- centrallix-lib/src/xstring.c | 14 +++++----- centrallix-lib/tests/test_foreign_00.c | 26 +++++++++++++++++ centrallix-os/tests/Foreign.csv | 4 +++ centrallix-os/tests/Foreign.spec | 15 ++++++++++ centrallix/expression/exp_functions.c | 7 +++++ centrallix/include/charsets.h | 2 +- .../tests/test_expfn_utf8reverse_00.cmp | 28 +++++++++++++++++++ centrallix/tests/test_expfn_utf8reverse_00.to | 6 ++++ centrallix/tests/test_overlong_00.to | 3 ++ centrallix/utility/charsets.c | 4 +-- 10 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 centrallix-lib/tests/test_foreign_00.c create mode 100644 centrallix-os/tests/Foreign.csv create mode 100644 centrallix-os/tests/Foreign.spec create mode 100755 centrallix/tests/test_expfn_utf8reverse_00.cmp create mode 100644 centrallix/tests/test_expfn_utf8reverse_00.to create mode 100644 centrallix/tests/test_overlong_00.to diff --git a/centrallix-lib/src/xstring.c b/centrallix-lib/src/xstring.c index ee5412aa7..4697d86be 100644 --- a/centrallix-lib/src/xstring.c +++ b/centrallix-lib/src/xstring.c @@ -320,7 +320,7 @@ xs_internal_Printf(pXString this, char* fmt, va_list vl) if (!str) str = "(null)"; do_as_string: /* from int handler, below */ - n = chrCharLength(str); + n = strlen(str); /** Need to pad beginning of string with spaces? **/ if (field_width > precision && precision >= 0) @@ -636,7 +636,7 @@ xsFindRev(pXString this,char* find,int findlen, int offset) CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(findlen==-1) findlen = chrCharLength(find); + if(findlen==-1) findlen = strlen(find); offset=this->Length-offset-1; for(;offset>=0;offset--) { @@ -678,8 +678,8 @@ xsSubst(pXString this, int offset, int len, char* rep, int replen) CXSEC_EXIT(XS_FN_KEY); return -1; } - if (len == -1) len = chrCharLength(this->String + offset); - if (replen == -1) replen = chrCharLength(rep); + if (len == -1) len = strlen(this->String + offset); + if (replen == -1) replen = strlen(rep); /** Make sure we have enough room **/ if (len < replen) xsCheckAlloc(this, replen - len); @@ -704,8 +704,8 @@ xsReplace(pXString this, char* find, int findlen, int offset, char* rep, int rep CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(findlen==-1) findlen = chrCharLength(find); - if(replen==-1) replen = chrCharLength(rep); + if(findlen==-1) findlen = strlen(find); + if(replen==-1) replen = strlen(rep); offset=xsFind(this,find,findlen,offset); if(offset < 0) { @@ -743,7 +743,7 @@ xsInsertAfter(pXString this, char* ins, int inslen, int offset) CXSEC_ENTRY(XS_FN_KEY); ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - if(inslen==-1) inslen = chrCharLength(ins); + if(inslen==-1) inslen = strlen(ins); if(xsCheckAlloc(this,inslen)==-1) { CXSEC_EXIT(XS_FN_KEY); diff --git a/centrallix-lib/tests/test_foreign_00.c b/centrallix-lib/tests/test_foreign_00.c new file mode 100644 index 000000000..8fd8ae879 --- /dev/null +++ b/centrallix-lib/tests/test_foreign_00.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include +#include + +long long +test(char** tname) + { + int i; + int iter; + + char* str1 = "Glück"; + char* str2 = "Χαίρετε"; + char* str3 = "\u0393"; + char* str4 = "\xce\x93"; + printf("%s\n%s\n%s\n%s\n", str1, str2, str3, str4); + + *tname = "Printing foreign characters"; + iter = 10000000; + for(i=0;i Date: Wed, 1 Jul 2020 17:06:45 -0600 Subject: [PATCH 029/124] Reverse works --- centrallix-os/tests/Foreign.csv | 9 +- centrallix/expression/exp_functions.c | 108 +++++++++++++++--- centrallix/tests/test_expfn_utf8replace_00.to | 4 + .../tests/test_expfn_utf8reverse_00.cmp | 10 ++ centrallix/tests/test_expfn_utf8reverse_00.to | 2 +- 5 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 centrallix/tests/test_expfn_utf8replace_00.to diff --git a/centrallix-os/tests/Foreign.csv b/centrallix-os/tests/Foreign.csv index 83c405ed0..a43348fcd 100644 --- a/centrallix-os/tests/Foreign.csv +++ b/centrallix-os/tests/Foreign.csv @@ -1,4 +1,11 @@ String ελπίδα Adiós -Glück +Glück +АДЖИ +français +Swạsdī +Салом +ρά +χ +тэд тэнд баривчилж байна diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 227bd1353..067968c40 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -761,6 +761,7 @@ int exp_fn_replicate(pExpression tree, pParamObjects objlist, pExpression i0, pE //i0 is haystack, i1 is needle, i2 is replacement int exp_fn_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + printf("Replacing\n"); char* repstr; long long newsize; char* srcptr; @@ -769,6 +770,7 @@ int exp_fn_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExp int searchlen, replen; if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) { + printf("UHOH\n"); tree->Flags |= EXPR_F_NULL; tree->DataType = DATA_T_STRING; return 0; @@ -3634,9 +3636,35 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, tree->String = tree->Types.StringBuf; } strcpy(tree->String, i0->String); - + /** Reversing string **/ - i = 0; + char *scanl, *scanr, *scanr2, c; + + /* first reverse the string */ + for (scanl= tree->String, scanr= tree->String + strlen(tree->String); scanl < scanr;) + c= *scanl, *scanl++= *--scanr, *scanr= c; + + /* then scan all bytes and reverse each multibyte character */ + for (scanl= scanr= tree->String; c= *scanr++;) + { + if ( (c & 0x80) == 0) // ASCII char + scanl= scanr; + else if ( (c & 0xc0) == 0xc0 ) // start of multibyte + { + scanr2= scanr; + switch (scanr - scanl) + { + case 4: c= *scanl, *scanl++= *--scanr, *scanr= c; // fallthrough + case 3: // fallthrough + case 2: c= *scanl, *scanl++= *--scanr, *scanr= c; + } + scanr= scanl= scanr2; + } + } + + + +/* i = 0; end = byteLen-1; temp = (char*)nmSysMalloc(sizeof(char) * byteLen+1); temp[byteLen] = '\0'; @@ -3644,19 +3672,21 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, for(a = 0; a < charLen; a++) { ch1 = tree->String[i]; - if ((ch1 & mask1) == 0x00)//maybe add helper functions instead of masks and validate following continuation bytes + if (ch1 < 0xC0)//maybe add helper functions instead of masks and validate following continuation bytes { + printf("1\n"); temp[end--] = ch1; i++; } - else if ((ch1 & mask2) == 0xC0) + else if (ch1 < 0xE0) { + printf("2\n"); ch2 = tree->String[++i]; temp[end--] = ch2; temp[end--] = ch1; i++; } - else if ((ch1 & mask3) == 0xE0) + else if (ch1 < 0xF0) { ch2 = tree->String[++i]; ch3 = tree->String[++i]; @@ -3665,7 +3695,7 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, temp[end--] = ch1; i++; } - else if ((ch1 & mask4) == 0xF0) + else// if ((ch1 & mask4) == 0xF0) { ch2 = tree->String[++i]; ch3 = tree->String[++i]; @@ -3676,20 +3706,22 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, temp[end--] = ch1; i++; } } - strcpy(tree->String, temp); +*/ + //strcpy(tree->String, temp); return 0; } int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - char* repstr; - long long newsize; - char* srcptr; - char* searchptr; - char* dstptr; - int searchlen, replen; - if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) + printf("Starting\n"); + char *haystack, *needle, *replace; + long long newsize, diff; + char* pos; + char *dstptr, *oldptr; + size_t len_replace, len_needle, len_haystack, num_shifts; + + if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) { tree->Flags |= EXPR_F_NULL; tree->DataType = DATA_T_STRING; return 0; } @@ -3698,16 +3730,53 @@ int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, return -1; } if (i2->Flags & EXPR_F_NULL) - repstr = ""; + replace = ""; else - repstr = i2->String; + replace = i2->String; if (tree->Alloc && tree->String) nmSysFree(tree->String); tree->Alloc = 0; - if (i1->String[0] == '\0') { tree->String = i0->String; - return 0; - } + if (i1->String[0] == '\0') + { + tree->String = i0->String; + return 0; + } + printf("Passed init stuff\n"); + fflush(stdout); + haystack = i0->String; + needle = i1->String; + printf("strcpy\n"); + len_haystack = strlen(haystack); + len_needle = strlen(needle); + len_replace = strlen(replace); + printf("lens\n"); + fflush(stdout); + dstptr = nmSysMalloc((len_haystack + 1) * sizeof(char)); + strcpy(dstptr, haystack); + printf("malloc\n"); + fflush(stdout); + pos = strstr(haystack, needle); + while(pos != NULL) + { + printf("Start while\n"); + fflush(stdout); + oldptr = dstptr; + len_haystack = strlen(dstptr); + diff = (long long) (len_replace - len_needle); + dstptr = nmSysMalloc((len_haystack + diff + 1) * sizeof(char)); + + num_shifts = pos - oldptr; + memcpy(dstptr, oldptr, num_shifts); + memcpy(dstptr + num_shifts, replace, len_replace); + memcpy(dstptr + num_shifts + len_replace, pos + len_needle, len_haystack + 1 - num_shifts - len_needle); + + //free(oldptr); + pos = strstr(haystack, needle); + } + + strcpy(tree->String, dstptr); + return 0; } int exp_fn_utf8_substitute(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) @@ -3779,6 +3848,7 @@ exp_internal_DefineFunctions() /** UTF-8/ASCII dependent **/ xhAdd(&EXP.Functions, "utf8_reverse", (char*) exp_fn_utf8_reverse); + xhAdd(&EXP.Functions, "utf8_replace", (char*) exp_fn_utf8_replace); xhAdd(&EXP.Functions, "overlong", (char*) exp_fn_utf8_overlong); if (CxGlobals.CharacterMode == CharModeSingleByte) { diff --git a/centrallix/tests/test_expfn_utf8replace_00.to b/centrallix/tests/test_expfn_utf8replace_00.to new file mode 100644 index 000000000..9b7fcc3c9 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8replace_00.to @@ -0,0 +1,4 @@ +##NAME utf8_replace() function + +query select utf8_replace("abcdefg","cd","x") + diff --git a/centrallix/tests/test_expfn_utf8reverse_00.cmp b/centrallix/tests/test_expfn_utf8reverse_00.cmp index 5819cea52..0e617c616 100755 --- a/centrallix/tests/test_expfn_utf8reverse_00.cmp +++ b/centrallix/tests/test_expfn_utf8reverse_00.cmp @@ -25,4 +25,14 @@ Attribute [column_000]: string "eulB" Attribute [column_000]: string "elpruP" Attribute [column_000]: string "egnarO" Attribute [column_000]: string "teloiV" +Attribute [column_000]: string "αδίπλε" +Attribute [column_000]: string "sóidA" +Attribute [column_000]: string "kcülG" +Attribute [column_000]: string "ИЖДА" +Attribute [column_000]: string "siaçnarf" +Attribute [column_000]: string "īdsạwS" +Attribute [column_000]: string "молаС" +Attribute [column_000]: string "άρ" +Attribute [column_000]: string "χ" +Attribute [column_000]: string "анйаб жличвираб днэт дэт" Attribute [utf8_reverse(null)]: string NULL diff --git a/centrallix/tests/test_expfn_utf8reverse_00.to b/centrallix/tests/test_expfn_utf8reverse_00.to index 25610769e..a474774a8 100644 --- a/centrallix/tests/test_expfn_utf8reverse_00.to +++ b/centrallix/tests/test_expfn_utf8reverse_00.to @@ -1,4 +1,4 @@ -##NAME exp_fn_utf8_reverse() function +##NAME utf8_reverse() function query select utf8_reverse(:f_string) from /tests/Datatypes.csv/rows query select utf8_reverse(:Color) from /tests/TestLevel1.csv/rows From 73aa9919b5a21396bd5c52e0fc1f863c111ab0c2 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Thu, 2 Jul 2020 11:54:30 -0600 Subject: [PATCH 030/124] Overlong Testing --- centrallix/.Makefile.swp | Bin 16384 -> 0 bytes centrallix/expression/exp_functions.c | 14 ++++++++++++-- centrallix/tests/test_overlong_00.to | 4 ++++ centrallix/utility/charsets.c | 14 +++++++++----- 4 files changed, 25 insertions(+), 7 deletions(-) delete mode 100644 centrallix/.Makefile.swp diff --git a/centrallix/.Makefile.swp b/centrallix/.Makefile.swp deleted file mode 100644 index c47b09aee97e13c6905029861b1fe2b37b721f5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHNZEPb)8J?Cxdo69D6$n8Q(!9m0YyMTq6k5uJTp6MZ*1Q+ zlwYX3(qr$=JM+#v&pSJ_@4MStI9pk#x8|1!j#m-#t^8l!_3f+gyX?Ws2=O@&Mez$A zyUyam;zAHP4)c#)qH-Y${DRF5-7W;aQ80SBjujRR=7zp*+g7izuJ5q6WwT4@$V3?f z83QktfosX}#bXPi_4L%u^u`;`yjVq9yNrR1fsBESfsBESfsBESfsBESf&W7WLhnlQ zKG=P^vi&~wkMLg}$^Y}}_>3xl|A_qGN`6k2zfLtw+W$+*x0L(?Bl72zysqRw9+Cf3 z$y-W3uMAG~|3k@-D)|E=a#fuDWej8tWDH~sWDH~sWDH~sWDH~sWDH~sWDL9{8PLsm z*f)uI8Snq^Q!M=EdP05)d;$0@umM~JJbE1=0q|zv7uOQ<6X26T1$h3IgggRxzz#rx zzg|PgGr*sKKLS4kehPdacntV5@M+*vKp(gpxD|LKa5?bns|k4=cnJ6y-~b!IGH?g* zCg4Wk2H@4emB4d{2zeTK3iu)L81OLgAn+dG-N4&`Jdgvf0Qy%E(gW6kr>`XBo4_}K z`++^c0=9v5U>TSNt_S}93fKtz2zUZ`6!;48An;M(Uf=?-0jvWHz#D+q1HXGYA-@G4 z0v-VN03BEdZUd%(Yk+63AmmrTcY&`0p94M!oCiGMEx;0R6L2~3^vekO0q}L;OThg= z2;2>nfd$|w@HhDUS>PkUoxmD!3n1qL=D{H<58gUw`n%1bA6Rai=Q+KHY@I#6dFt(} z^~%|DU0X&08CKgJP%CY+GT!FI6OZyw>4V%$PqGDwoFyO zoeP$i4|sCf4a4-MV>v7(b^5`1J9XW2(pOH4_aIDJdq6uiSSZe{e50PAMrs#;v1*>7-W5H+x%k47XN)0@&ANujYh7-H#>AvoawKupM z;SlpGx;w~7lCA`sebSoCY8QOZ4 zI^2wG7SOP(htzUBn>jEPmn@c-Y8Be%KE)(qzN_1Gg~HQ>lxnqVX}etC?=Ibwe23^i z_Eu6&cxo%TSVlEv2$`lO&!g+Qt9Rm_t9qaLbgr~sMHB5zt+rWj?C&HBE!ztFaR;hK zJQL0Z+-(Z6oCUnqjsimu6E`#0G5IxHC8dR_3IwCIM8ovs^%&A}wz zN|*}5VU=mBMV`2i2VTzQXiE<)gX*qHb#qsD4QA4qPz%!@-|?I(X_b{r5H97QdwMIb z>4bV9RxKyASx+tjJ>BTodrsza=XvzDlDA?>Ux9GA^Eks4jHSEY_#dz^6 zhAhB_V}-29uu8^vRgr~8ajz5lMWYu4MMrnzYQ@ydhuP8?nxhz>yp>GLhgsYQ$8?WT zG{bZU+iUNv)aWuTv@EwE_9ar;&>E#`wYgeqlpvV7R~5XM<{Wy<($b)Uwow~IRB&{$If**)MsKt`iBavyHKefZbBEf2+$!Ux zQY-~ctSxz5h7|X@&+*)Z`9VD!J4A5v&6Jj0b6yQkJeg733c`8XVm9BycveRE0& zX^;=HvjNPrLQA);3(`WRDPEeSx!95Ay)iFGXN3X9S}A)HgMoD4W=}CwExl#4*+8kP zv}vD5v+#u_oMQ!XW1I6GEY5P1@AAEbJ)L5G77t5<vkiBb} z(6wiU-B?G!+ufv8YKZZnAZR0X}O9f=c?3JI;Cw^&os)_ zZMw0kG>N!E%n{y})~s!up=-4&^`aJB+Jzmhz7(9s12xqWOHOl)QMwKe3YDsO*onf$ zeJYvD@R>TT3AF~T#;nX!JZtH0pW2vQ$?;u=!yiJ2D0`1~LXR1~LXR23`UTsCbg*P39p>gaCe3o*r9bDzJ*e_(swtvMnzQW|9=+pEhslltPMfx=i`;h+ z&-zIcWLOTvrpGKhsco#+n(=r~9?+z?O|^1LLkl_f=|N_ufCxjr3~-UU6_!kvOeD!R zF}nYP@iEolWoL4yQZljA*fYt5Ibiq7CswPF&llj7Tb8I|V$3G>c47h%Qu4w!3H^9W zv3O8wCfJsh>AWg7078zJ=WLzxb?Km5cAPccB@&gE9TZrNN z$Rpx~)gB`1Bs@2|%-E4RkwJw*6M_nAF980O;{`#sB~S diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 067968c40..a2146dca9 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -3231,9 +3231,19 @@ int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpres return 0; } -char* exp_fn_utf8_overlong(char* string) +int exp_fn_utf8_overlong(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - return chrNoOverlong(string); + printf("EXP\nRecieved String: %s\n", i0->String); + char* str = chrNoOverlong(i0->String); + printf("A"); + fflush(stdout); + printf("Final str: %s\n", str); + printf("B"); + fflush(stdout); + tree->String = str; + printf("C"); + fflush(stdout); + return 0; } int exp_fn_utf8_ascii(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) diff --git a/centrallix/tests/test_overlong_00.to b/centrallix/tests/test_overlong_00.to index 3da7322a1..569ae7ffa 100644 --- a/centrallix/tests/test_overlong_00.to +++ b/centrallix/tests/test_overlong_00.to @@ -1,3 +1,7 @@ ##NAME overlong function query select overlong("abc") +query select overlong("\\x21") +query select overlong("\\xC0\\xA1") +query select overlong("\\xE2\\x82\\xAC") +query select overlong("\\xF0\\x82\\x82\\xAC") diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c index 19d0a4eba..be4b67c27 100755 --- a/centrallix/utility/charsets.c +++ b/centrallix/utility/charsets.c @@ -324,6 +324,7 @@ size_t chrCharLength(char* string) char* chrNoOverlong(char* string) { + printf("No Overlong\nInit String: %s\n", string); size_t stringCharLength, newStrByteLength; char* toReturn; wchar_t* longBuffer; @@ -331,19 +332,20 @@ char* chrNoOverlong(char* string) /** Check arguments **/ if(!string) return CHR_INVALID_ARGUMENT; - + stringCharLength = mbstowcs(NULL, string, 0); if(stringCharLength == (size_t)-1) { return NULL; } - + printf("Args checked\n"); /** Create wchar_t buffer */ longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); if(!longBuffer) return NULL; mbstowcs(longBuffer, string, stringCharLength + 1); - + printf("Made wide buffer\n"); + wprintf(L"Wide String: %ls\n, longBuffer"); /** Convert back to MBS **/ newStrByteLength = wcstombs(NULL, longBuffer, 0); if(newStrByteLength == (size_t)-1) @@ -351,7 +353,7 @@ char* chrNoOverlong(char* string) nmSysFree(longBuffer); return NULL; } - + printf("got size\n"); toReturn = (char *)nmSysMalloc(newStrByteLength + 1); if(!toReturn) { @@ -360,7 +362,9 @@ char* chrNoOverlong(char* string) } wcstombs(toReturn, longBuffer, newStrByteLength + 1); - nmSysFree(longBuffer); + printf("String: %s\n", toReturn); + nmSysFree(longBuffer); + printf("Done\n"); //nmSysFree(string); //good? return toReturn; } From 080d1ab80bd5642e0b523a25cd817aacfac09bb2 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Thu, 2 Jul 2020 16:46:19 -0600 Subject: [PATCH 031/124] End of sprint --- centrallix/tests/test_expfn_utf8ascii_00.to | 8 +++++++ .../tests/test_expfn_utf8charindex_00.to | 22 +++++++++++++++++++ .../tests/test_expfn_utf8charlength_00.to | 8 +++++++ centrallix/tests/test_expfn_utf8lower_00.to | 6 +++++ centrallix/tests/test_expfn_utf8ralign_00.to | 14 ++++++++++++ centrallix/tests/test_expfn_utf8right_00.to | 13 +++++++++++ .../tests/test_expfn_utf8substring_00.to | 14 ++++++++++++ centrallix/tests/test_expfn_utf8upper_00.to | 6 +++++ centrallix/tests/test_overlong_00.to | 2 +- 9 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 centrallix/tests/test_expfn_utf8ascii_00.to create mode 100644 centrallix/tests/test_expfn_utf8charindex_00.to create mode 100644 centrallix/tests/test_expfn_utf8charlength_00.to create mode 100644 centrallix/tests/test_expfn_utf8lower_00.to create mode 100644 centrallix/tests/test_expfn_utf8ralign_00.to create mode 100644 centrallix/tests/test_expfn_utf8right_00.to create mode 100644 centrallix/tests/test_expfn_utf8substring_00.to create mode 100644 centrallix/tests/test_expfn_utf8upper_00.to diff --git a/centrallix/tests/test_expfn_utf8ascii_00.to b/centrallix/tests/test_expfn_utf8ascii_00.to new file mode 100644 index 000000000..3fa90b0b7 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8ascii_00.to @@ -0,0 +1,8 @@ +##NAME ascii() function + +query select 'ascii("A")' = ascii("A") +query select 'ascii("Ab")' = ascii("Ab") +query select 'ascii("1")' = ascii("1") +query select 'ascii("10")' = ascii("10") +query select 'ascii(null)' = ascii(null) +query select 'ascii("")' = ascii("") diff --git a/centrallix/tests/test_expfn_utf8charindex_00.to b/centrallix/tests/test_expfn_utf8charindex_00.to new file mode 100644 index 000000000..1dfdde062 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8charindex_00.to @@ -0,0 +1,22 @@ +##NAME charindex() function + +query select 'charindex("abc", "abcdefg")' = charindex("abc", "abcdefg") +query select 'charindex("cde", "abcdefg")' = charindex("cde", "abcdefg") +query select 'charindex("efg", "abcdefg")' = charindex("efg", "abcdefg") +query select 'charindex("fgh", "abcdefg")' = charindex("fgh", "abcdefg") +query select 'charindex("1ab", "abcdefg")' = charindex("1ab", "abcdefg") +query select 'charindex("a", "abcdefg")' = charindex("a", "abcdefg") +query select 'charindex("d", "abcdefg")' = charindex("d", "abcdefg") +query select 'charindex("g", "abcdefg")' = charindex("g", "abcdefg") +query select 'charindex("h", "abcdefg")' = charindex("h", "abcdefg") +query select 'charindex("1", "abcdefg")' = charindex("1", "abcdefg") +query select 'charindex("abc", "a")' = charindex("abc", "a") +query select 'charindex("abc", "abc")' = charindex("abc", "abc") +query select 'charindex("", "abcdefg")' = charindex("", "abcdefg") +query select 'charindex("a", "")' = charindex("a", "") +query select 'charindex("", "")' = charindex("", "") +query select 'charindex(null, "abcdefg")' = charindex(null, "abcdefg") +query select 'charindex("a", null)' = charindex("a", null) +query select 'charindex(null, null)' = charindex(null, null) +query select 'charindex("", null)' = charindex("", null) +query select 'charindex(null, "")' = charindex(null, "") diff --git a/centrallix/tests/test_expfn_utf8charlength_00.to b/centrallix/tests/test_expfn_utf8charlength_00.to new file mode 100644 index 000000000..6b4f318c5 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8charlength_00.to @@ -0,0 +1,8 @@ +##NAME char_length() function + +query select 'char_length("abc")' = char_length("abc") +query select 'char_length("a")' = char_length("a") +query select 'char_length("")' = char_length("") +query select 'char_length(null)' = char_length(null) +query select 'char_length("abcde"*999999)' = char_length("abcde" * 999999) +query select 'char_length("كتاب")' = char_length("كتاب") diff --git a/centrallix/tests/test_expfn_utf8lower_00.to b/centrallix/tests/test_expfn_utf8lower_00.to new file mode 100644 index 000000000..386819690 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8lower_00.to @@ -0,0 +1,6 @@ +##NAME lower() function + +query select lower(:f_string) from /tests/Datatypes.csv/rows +query select lower(:Color) from /tests/TestLevel1.csv/rows +query select lower(null) +query select lower("\t") diff --git a/centrallix/tests/test_expfn_utf8ralign_00.to b/centrallix/tests/test_expfn_utf8ralign_00.to new file mode 100644 index 000000000..43775511f --- /dev/null +++ b/centrallix/tests/test_expfn_utf8ralign_00.to @@ -0,0 +1,14 @@ +##NAME ralign() function + +query select 'ralign("Test", 5)' = ralign("Test", 10) + +query select 'ralign("Test", 0)' = ralign("Test", 0) + +query select 'ralign("Test", -50)' = ralign("Test", -10) + +query select 'ralign("",5)' = ralign("",5) + +query select 'ralign(null,1)' = ralign(null,1) + +query select ralign(:f_string,20) from /tests/Datatypes.csv/rows + diff --git a/centrallix/tests/test_expfn_utf8right_00.to b/centrallix/tests/test_expfn_utf8right_00.to new file mode 100644 index 000000000..9117eaad1 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8right_00.to @@ -0,0 +1,13 @@ +##NAME right() function + +query select 'right("abcde", 3)' = right("abcde", 3) + +query select 'right("abcde", 8)' = right("abcde", 8) + +query select 'right("abcde", 0)' = right("abcde", 0) + +query select 'right("abcde\"", 6)' = right("abcde\"", 6) + +query select 'right("", 1)' = right("", 1) + +query select 'right(null, null)' = right(null, null) diff --git a/centrallix/tests/test_expfn_utf8substring_00.to b/centrallix/tests/test_expfn_utf8substring_00.to new file mode 100644 index 000000000..6bc01b616 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8substring_00.to @@ -0,0 +1,14 @@ +##NAME substring function + +query select substring("abcde", 3, 2) +query select substring("abcde", 4) +query select substring("abcde",-1) +query select substring("abcde", -3, 2) +query select substring("abc", 3, 2) +query select substring("abcde", 3, -2) +query select substring(null, 1, 1) +query select substring("string", null, 1) +query select substring("string", 1) +query select substring("a slightly longer string", 10, 50) +query select substring("\\", 1, 1) +query select substring("", 1, 1) diff --git a/centrallix/tests/test_expfn_utf8upper_00.to b/centrallix/tests/test_expfn_utf8upper_00.to new file mode 100644 index 000000000..7f6691f3b --- /dev/null +++ b/centrallix/tests/test_expfn_utf8upper_00.to @@ -0,0 +1,6 @@ +##NAME upper() function + +query select upper(:f_string) from /tests/Datatypes.csv/rows +query select upper(:Color) from /tests/TestLevel1.csv/rows +query select upper(null) +query select upper("\t") diff --git a/centrallix/tests/test_overlong_00.to b/centrallix/tests/test_overlong_00.to index 569ae7ffa..895cd9e31 100644 --- a/centrallix/tests/test_overlong_00.to +++ b/centrallix/tests/test_overlong_00.to @@ -1,7 +1,7 @@ ##NAME overlong function query select overlong("abc") -query select overlong("\\x21") +query select overlong("\x21") query select overlong("\\xC0\\xA1") query select overlong("\\xE2\\x82\\xAC") query select overlong("\\xF0\\x82\\x82\\xAC") From ce5195cd42e42825301c6b04dbf07ff6e0f23ef7 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Tue, 7 Jul 2020 17:28:17 -0600 Subject: [PATCH 032/124] EXP FUNCTIONS --- centrallix-lib/tests/test_foreign_01.c | 61 + centrallix-os/tests/Foreign2.csv | 2 + centrallix-os/tests/Foreign2.spec | 16 + centrallix-os/tests/Foreign3.csv | 9 + centrallix-os/tests/Foreign3.spec | 17 + centrallix/expression/exp_functions.c | 31 +- centrallix/osdrivers/fake.c | 3361 +++++++++++++++++ centrallix/osdrivers/fake2.c | 646 ++++ .../tests/test_expfn_char_length_00.cmp | 1 - centrallix/tests/test_expfn_char_length_00.to | 1 - .../tests/test_expfn_utf8charindex_00.to | 64 +- .../tests/test_expfn_utf8charlength_00.cmp | 16 + .../tests/test_expfn_utf8charlength_00.to | 13 +- .../tests/test_expfn_utf8replace_00.cmp | 31 + centrallix/tests/test_expfn_utf8replace_00.to | 33 +- centrallix/tests/test_expfn_utf8sub_00.cmp | 76 + centrallix/tests/test_expfn_utf8sub_00.to | 24 + centrallix/tests/test_overlong_00.to | 4 +- 18 files changed, 4364 insertions(+), 42 deletions(-) create mode 100644 centrallix-lib/tests/test_foreign_01.c create mode 100644 centrallix-os/tests/Foreign2.csv create mode 100644 centrallix-os/tests/Foreign2.spec create mode 100644 centrallix-os/tests/Foreign3.csv create mode 100644 centrallix-os/tests/Foreign3.spec create mode 100644 centrallix/osdrivers/fake.c create mode 100644 centrallix/osdrivers/fake2.c create mode 100755 centrallix/tests/test_expfn_utf8charlength_00.cmp create mode 100755 centrallix/tests/test_expfn_utf8replace_00.cmp create mode 100755 centrallix/tests/test_expfn_utf8sub_00.cmp create mode 100644 centrallix/tests/test_expfn_utf8sub_00.to diff --git a/centrallix-lib/tests/test_foreign_01.c b/centrallix-lib/tests/test_foreign_01.c new file mode 100644 index 000000000..33c7e4ab6 --- /dev/null +++ b/centrallix-lib/tests/test_foreign_01.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +long long +test(char** tname) + { + int i; + int iter; + + setlocale(LC_CTYPE, ""); + wchar_t str[] = L"ﺎﻟﺮﺧﺎﻣ"; + //int bytes = (int)strlen(str); + //printf("bytes: %d\n", bytes); + wprintf(str); + //fflush(stdout); + wprintf(L"\n"); + wchar_t ch1 = L'ﺍ'; + wchar_t ch2 = L'ﻝ'; + wchar_t ch3 = L'ﺭ'; + wchar_t ch4 = L'ﺥ'; + wchar_t ch5 = L'ﺍ'; + wchar_t ch6 = L'ﻡ'; + wchar_t word[13]; + word[0] = ch1; + word[1] = ch2; + word[2] = ch3; + word[3] = ch4; + word[4] = ch5; + word[5] = ch6; + word[6] = '\0'; + wchar_t rev[7]; + rev[0] = ch6; + rev[1] = ch5; + rev[2] = ch4; + rev[3] = ch3; + rev[4] = ch2; + rev[5] = ch1; + rev[6] = '\0'; + + //wprintf("str: %ls\n", str); + wprintf(word); + wprintf(L"\n"); + wprintf(rev); + wprintf(L"\n"); + + + + + *tname = "Printing Arabic"; + iter = 10000000; + for(i=0;iFlags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) { - printf("UHOH\n"); tree->Flags |= EXPR_F_NULL; tree->DataType = DATA_T_STRING; return 0; @@ -1026,6 +1024,8 @@ int exp_fn_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpre int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { + printf("Substring\n"); + fflush(stdout); int i,n; char* ptr; @@ -1045,15 +1045,21 @@ int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pE mssError(1,"EXP","Invalid datatypes in substring() - takes (string,integer,[integer])"); return -1; } + printf("Passed\n"); + printf("String: %s\n", i0->String); + fflush(stdout); n = strlen(i0->String); i = i1->Integer-1; if (i<0) i = 0; if (i > n) i = n; ptr = i0->String + i; + printf("Indexed string: %s\n", ptr); + fflush(stdout); i = i2?(i2->Integer):(strlen(ptr)); if (i < 0) i = 0; if (i > strlen(ptr)) i = strlen(ptr); - + printf("Num chars: %d", i); + fflush(stdout); /** Ok, got position and length. Now make new string in tree-> **/ if (tree->Alloc && tree->String) { @@ -3722,7 +3728,7 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, return 0; } -int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) +/*int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { printf("Starting\n"); char *haystack, *needle, *replace; @@ -3731,8 +3737,10 @@ int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, char *dstptr, *oldptr; size_t len_replace, len_needle, len_haystack, num_shifts; - if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) - { tree->Flags |= EXPR_F_NULL; tree->DataType = DATA_T_STRING; + if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) + { + tree->Flags |= EXPR_F_NULL; + tree->DataType = DATA_T_STRING; return 0; } if (!i0 || i0->DataType != DATA_T_STRING || !i1 || i1->DataType != DATA_T_STRING || !i2 || (!(i2->Flags & EXPR_F_NULL) && i2->DataType != DATA_T_STRING)) @@ -3793,6 +3801,7 @@ int exp_fn_utf8_substitute(pExpression tree, pParamObjects objlist, pExpression { return 0; } +*/ int exp_internal_DefineFunctions() @@ -3839,6 +3848,8 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "log10", (char*)exp_fn_log10); xhAdd(&EXP.Functions, "power", (char*)exp_fn_power); xhAdd(&EXP.Functions, "pbkdf2", (char*)exp_fn_pbkdf2); + xhAdd(&EXP.Functions, "replace", (char*) exp_fn_replace); + xhAdd(&EXP.Functions, "substitute", (char*) exp_fn_substitute); /** Windowing **/ xhAdd(&EXP.Functions, "row_number", (char*)exp_fn_row_number); @@ -3858,8 +3869,9 @@ exp_internal_DefineFunctions() /** UTF-8/ASCII dependent **/ xhAdd(&EXP.Functions, "utf8_reverse", (char*) exp_fn_utf8_reverse); - xhAdd(&EXP.Functions, "utf8_replace", (char*) exp_fn_utf8_replace); xhAdd(&EXP.Functions, "overlong", (char*) exp_fn_utf8_overlong); + xhAdd(&EXP.Functions, "utf8_charindex", (char*) exp_fn_utf8_charindex); + xhAdd(&EXP.Functions, "utf8_char_length", (char*) exp_fn_utf8_char_length); if (CxGlobals.CharacterMode == CharModeSingleByte) { xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); @@ -3872,8 +3884,6 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_escape); xhAdd(&EXP.Functions, "reverse", (char*) exp_fn_reverse); - xhAdd(&EXP.Functions, "replace", (char*) exp_fn_replace); - xhAdd(&EXP.Functions, "substitute", (char*) exp_fn_substitute); } else { @@ -3886,10 +3896,7 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "right", (char*) exp_fn_utf8_right); xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); - xhAdd(&EXP.Functions, "reverse", (char*) exp_fn_utf8_reverse); - xhAdd(&EXP.Functions, "replace", (char*) exp_fn_utf8_replace); - xhAdd(&EXP.Functions, "substitute", (char*) exp_fn_utf8_substitute); } return 0; diff --git a/centrallix/osdrivers/fake.c b/centrallix/osdrivers/fake.c new file mode 100644 index 000000000..9bf45b819 --- /dev/null +++ b/centrallix/osdrivers/fake.c @@ -0,0 +1,3361 @@ +#include +#include +#include +#include +#include +#include "obj.h" +#include "cxlib/mtask.h" +#include "cxlib/xarray.h" +#include "cxlib/xhash.h" +#include "stparse.h" +#include "st_node.h" +#include "hints.h" +#include "cxlib/mtsession.h" +#include "centrallix.h" +#include "cxlib/strtcpy.h" +#include "cxlib/qprintf.h" +#include "cxlib/util.h" +#include +#include + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2008 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: objdrv_mysql.c */ +/* Author: Greg Beeley (GB) */ +/* Creation: February 21, 2008 */ +/* Description: A MySQL driver for Centrallix. Eventually this driver */ +/* should be merged with the Sybase driver in something of */ +/* an intelligent manner. */ +/************************************************************************/ + + +#define MYSD_MAX_COLS 256 +#define MYSD_MAX_KEYS 8 +#define MYSD_NAME_LEN 32 +#define MYSD_MAX_CONN 16 + +#define MYSD_NODE_F_USECXAUTH 1 /* use Centrallix usernames/passwords */ +#define MYSD_NODE_F_SETCXAUTH 2 /* try to change empty passwords to Centrallix login passwords */ + +/*** Node ***/ +typedef struct + { + char Path[OBJSYS_MAX_PATH]; + char Server[64]; + char Username[64]; + char Password[64]; + char DefaultPassword[64]; + char Database[MYSD_NAME_LEN]; + char AnnotTable[MYSD_NAME_LEN]; + char Description[256]; + int MaxConn; + int Flags; + pSnNode SnNode; + XArray Conns; + int ConnAccessCnt; + XHashTable Tables; + XArray Tablenames; + int LastAccess; + } + MysdNode, *pMysdNode; + + +/*** Connection data ***/ +typedef struct + { + MYSQL Handle; + char Username[64]; + char Password[64]; + pMysdNode Node; + int Busy; + int LastAccess; + } + MysdConn, *pMysdConn; + + +/*** Table data ***/ +typedef struct + { + char Name[MYSD_NAME_LEN]; + unsigned char ColFlags[MYSD_MAX_COLS]; + unsigned char ColCxTypes[MYSD_MAX_COLS]; + unsigned char ColKeys[MYSD_MAX_COLS]; + char* Cols[MYSD_MAX_COLS]; + char* ColTypes[MYSD_MAX_COLS]; + unsigned int ColLengths[MYSD_MAX_COLS]; + pObjPresentationHints ColHints[MYSD_MAX_COLS]; + int nCols; + char* Keys[MYSD_MAX_KEYS]; + int KeyCols[MYSD_MAX_KEYS]; + int nKeys; + pMysdNode Node; + char* Annotation; + pParamObjects ObjList; + pExpression RowAnnotExpr; + } + MysdTable, *pMysdTable; + +#define MYSD_COL_F_NULL 1 /* column allows nulls */ +#define MYSD_COL_F_PRIKEY 2 /* column is part of primary key */ +#define MYSD_COL_F_UNSIGNED 4 /* Flag for unsigned on integer fields */ + + +/*** Structure used by this driver internally. ***/ +typedef struct + { + Pathname Pathname; + char* Name; + int Type; + int Flags; + pObject Obj; + int Mask; + int CurAttr; + pMysdNode Node; + char* RowBuf; + MYSQL_ROW Row; + MYSQL_RES * Result; + char* ColPtrs[MYSD_MAX_COLS]; + unsigned short ColLengths[MYSD_MAX_COLS]; + pMysdTable TData; + union + { + DateTime Date; + MoneyType Money; + IntVec IV; + StringVec SV; + } Types; + char Objname[256]; + } + MysdData, *pMysdData; + +#define MYSD_T_DATABASE 1 +#define MYSD_T_TABLE 2 +#define MYSD_T_COLSOBJ 3 +#define MYSD_T_ROWSOBJ 4 +#define MYSD_T_COLUMN 5 +#define MYSD_T_ROW 6 + + +#define MYSD(x) ((pMysdData)(x)) + +/*** Structure used by queries for this driver. ***/ +typedef struct + { + pMysdData Data; + char NameBuf[256]; + XString Clause; + int ItemCnt; + } + MysdQuery, *pMysdQuery; + + +/*** GLOBALS ***/ +struct + { + XHashTable DBNodesByPath; + XArray DBNodeList; + int AccessCnt; + int LastAccess; + } + MYSD_INF; + +MYSQL_RES* mysd_internal_RunQuery(pMysdNode node, char* stmt, ...); +MYSQL_RES* mysd_internal_RunQuery_conn(pMysdConn conn, pMysdNode node, char* stmt, ...); +MYSQL_RES* mysd_internal_RunQuery_conn_va(pMysdConn conn, pMysdNode node, char* stmt, va_list ap); + +/** This value is returned if the query failed. If NULL is returned from + * ** the RunQuery functions, it means "no result set" but success. It is + * ** equal to 0xFFFFFFFF on 32-bit platforms, and 0xFFFFFFFFFFFFFFFFLL on + * ** 64-bit platforms. + * **/ +#define MYSD_RUNQUERY_ERROR ((MYSQL_RES*)~((long)0)) + +/*** mysd_internal_GetConn() - given a specific database node, get a connection + * *** to the server with a given login (from mss thread structures). + * ***/ +pMysdConn +mysd_internal_GetConn(pMysdNode node) + { + MYSQL_RES * result; + pMysdConn conn; + int i, conn_cnt, found; + int min_access; + char* username; + char* password; + + /** Is one available from the node's connection pool? **/ + conn_cnt = xaCount(&node->Conns); + + /** Use system auth? **/ + if (node->Flags & MYSD_NODE_F_USECXAUTH) + { + /** Do we have permission to do this? **/ + if (!(CxGlobals.Flags & CX_F_ENABLEREMOTEPW)) + { + mssError(1,"MYSD","use_system_auth requested, but Centrallix global enable_send_credentials is turned off"); + return NULL; + } + + /** Get usernamename/password from session **/ + username = mssUserName(); + password = mssPassword(); + + if(!username || !password) + { + mssError(1,"MYSD","Connect to database: username and/or password not supplied"); + return NULL; + } + } + else + { + /** Use usernamename/password from node **/ + username = node->Username; + password = node->Password; + } + + conn = NULL; + for(i=0;iConns, i); + if (!conn->Busy && !strcmp(username, conn->Username) && !strcmp(password, conn->Password)) + { + if (mysql_ping(&conn->Handle) != 0) + { + /** Got disconnected. Discard the connection. **/ + mysql_close(&conn->Handle); + memset(conn->Password, 0, sizeof(conn->Password)); + xaRemoveItem(&node->Conns, i); + nmFree(conn, sizeof(MysdConn)); + i--; + conn_cnt--; + conn = NULL; + continue; + } + break; + } + conn = NULL; + } + + /** Didn't get one? **/ + if (!conn) + { + if (conn_cnt < node->MaxConn) + { + /** Below pool maximum? Alloc if so **/ + conn = (pMysdConn)nmMalloc(sizeof(MysdConn)); + if (!conn) + { + mssError(0,"MYSD","Could not connect to database server"); + return NULL; + } + conn->Node = node; + } + else + { + /** Try to free and reuse a connection **/ + min_access = 0x7fffffff; + found = -1; + for(i=0;iConns, i); + if (!conn->Busy && conn->LastAccess < min_access) + { + min_access = conn->LastAccess; + found = i; + } + } + if (found < 0) + { + mssError(1, "MYSD", "Connection limit (%d) reached for server [%s]", + node->MaxConn, node->Server); + return NULL; + } + conn = (pMysdConn)xaGetItem(&node->Conns, found); + mysql_close(&conn->Handle); + memset(conn->Password, 0, sizeof(conn->Password)); + xaRemoveItem(&node->Conns, found); + nmFree(conn, sizeof(MysdConn)); + } + + /** Attempt connection **/ + if (mysql_init(&conn->Handle) == NULL) + { + mssError(1, "MYSD", "Memory exhausted"); + nmFree(conn, sizeof(MysdConn)); + return NULL; + } + if (mysql_real_connect(&conn->Handle, node->Server, username, password, node->Database, 0, NULL, 0) == NULL) + { + if (node->Flags & MYSD_NODE_F_SETCXAUTH) + { + if (mysql_real_connect(&conn->Handle, node->Server, username, node->DefaultPassword, node->Database, 0, NULL, 0) == NULL) + { + mssError(1, "MYSD", "Could not connect to MySQL server [%s], DB [%s]: %s", + node->Server, node->Database, mysql_error(&conn->Handle)); + mysql_close(&conn->Handle); + nmFree(conn, sizeof(MysdConn)); + return NULL; + } + + /** Successfully connected using user default password. + * ** Now try to change the password. + * **/ + result = mysd_internal_RunQuery_conn(conn, node, "SET PASSWORD = PASSWORD('?')", password); + + if (result == MYSD_RUNQUERY_ERROR) + mssError(1, "MYSD", "Warning: could not update password for user [%s]: %s", + username, mysql_error(&conn->Handle)); + } + else + { + mssError(1, "MYSD", "Could not connect to MySQL server [%s], DB [%s]: %s", + node->Server, node->Database, mysql_error(&conn->Handle)); + mysql_close(&conn->Handle); + nmFree(conn, sizeof(MysdConn)); + return NULL; + } + } + + /** Success! **/ + strtcpy(conn->Username, username, sizeof(conn->Username)); + strtcpy(conn->Password, password, sizeof(conn->Password)); + xaAddItem(&node->Conns, conn); + } + + /** Make it busy **/ + conn->Busy = 1; + conn->LastAccess = (node->ConnAccessCnt++); + + return conn; + } + + +/*** mysd_internal_ReleaseConn() - release a connection back to the connection + * *** pool. Also sets the pointer to NULL. + * ***/ +void +mysd_internal_ReleaseConn(pMysdConn * conn) + { + + /** Release it **/ + assert((*conn)->Busy); + (*conn)->Busy = 0; + (*conn) = NULL; + + return; + } + +/*** mysd_internal_RunQuery() - safely runs a query on the database + * *** This works simarly to prepared statments using the question mark syntax. + * *** Instead of calling bindParam for each argument as is done in general, + * *** all of the arguments to be replaced are passed as varargs + * *** + * *** There are some differences: + * *** ?d => decimal. inserts using sprintf("%d",int) + * *** ?v => quoted or nonquoted, params are (char* str, int add_quote), see ?a. + * *** ?q => used for query clauses. + * *** same as ? except without escaping + * *** only use if you know the input is clean and is already a query segment + * *** ?a => array, params for this are (char** array, char add_quote[], int length, char separator + * *** it will become: item1,item2,items3 (length = 3, separator = ',') + * *** '?a' => same as array except with individual quoting specified + * *** it will become: 'item1','item2','items3' (length = 3, separator = ',') + * *** ?n => transform name of object into criteria (field1 = 'value1' and field2 = 'value2') + * *** add_quote can be left NULL, in which case nothing gets quoted with ?a. + * *** (add_quote has no effect on '?a' forms). Otherwise, a non-'\0' value + * *** for add_quote[x] means to add single quotes '' onto the value. + * *** + * *** All parameters are sanatized with mysql_real_escape_string before + * *** the query is built + * *** This WILL NOT WORK WITH BINARY DATA + * ***/ +MYSQL_RES* +mysd_internal_RunQuery_conn_va(pMysdConn conn, pMysdNode node, char* stmt, va_list ap) + { + MYSQL_RES * result = MYSD_RUNQUERY_ERROR; + XString query; + int i, j; + int length = 0; + char * start; + char ** array = NULL; + int items = 0; + char separator; + char quote = 0x00; + char tmp[32]; + char * add_quote; + char * str; + char * endstr; + int err; + char * errtxt; + char ch; + pMysdData data; + + xsInit(&query); + + length=-1; + start=stmt; + for(i = 0; stmt[i]; i++) + { + length++; + if(stmt[i] == '?') + { + /** throw on everything new that is just constant **/ + if(xsConcatenate(&query,start,length)) goto error; + /** do the insertion **/ + if(stmt[i+1]=='a') /** handle arrays **/ + { + array = va_arg(ap,char**); + add_quote = va_arg(ap,char*); + items = va_arg(ap,int); + separator = va_arg(ap,int); + if(stmt[i+2] == '\'' || stmt[i+2]=='`') quote = stmt[i+2]; else quote = 0x00; + for(j = 0; j < items; j++) + { + if(j > 0) + { + if(quote) if(xsConcatenate(&query,"e,1)) goto error; + if(xsConcatenate(&query,&separator,1)) goto error; + if(quote) if(xsConcatenate(&query,"e,1)) goto error; + } + if (!array[j]) + { + xsConcatenate(&query, "null", 4); + } + else + { + if (!quote && add_quote && add_quote[j]) + xsConcatenate(&query, "'", 1); + if(mysd_internal_SafeAppend(&conn->Handle,&query,array[j])) goto error; + if (!quote && add_quote && add_quote[j]) + xsConcatenate(&query, "'", 1); + } + } + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='v') /** quoted / nonquoted **/ + { + str = va_arg(ap,char*); + quote = va_arg(ap,int); + if (!str) + { + xsConcatenate(&query, "null", 4); + } + else + { + if (quote) + xsConcatenate(&query, "'", 1); + if(mysd_internal_SafeAppend(&conn->Handle,&query,str)) goto error; + if (quote) + xsConcatenate(&query, "'", 1); + } + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='d') /** handle integers **/ + { + sprintf(tmp,"%d",va_arg(ap,int)); + if(mysd_internal_SafeAppend(&conn->Handle,&query,tmp)) goto error; + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='q') /** handle pre-sanitized query sections **/ + { + xsConcatenate(&query,va_arg(ap,char*),-1); + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='n') /** object name criteria - expect pMysdData **/ + { + data = va_arg(ap, pMysdData); + xsConcatenate(&query, " (", 2); + str = data->Name; + for(j=0; jTData->nKeys; j++) + { + endstr = strchr(str, '|'); + if (!endstr) + endstr = str + strlen(str); + if (j != 0) + xsConcatenate(&query, " and ", 5); + xsConcatenate(&query, "`", 1); + if (mysd_internal_SafeAppend(&conn->Handle, &query, data->TData->Keys[j])) goto error; + xsConcatenate(&query, "` = '", 5); + ch = *endstr; + *endstr = '\0'; + if (mysd_internal_SafeAppend(&conn->Handle, &query, str)) + { + *endstr = ch; + goto error; + } + *endstr = ch; + xsConcatenate(&query, "'", 1); + str = (*endstr)?(endstr+1):(endstr); + } + xsConcatenate(&query, ") ", 2); + start = &stmt[i+2]; + i++; + } + else /** handle plain sanitize+insert **/ + { + if(mysd_internal_SafeAppend(&conn->Handle,&query,va_arg(ap,char*))) goto error; + start = &stmt[i+1]; + } + length = -1; + } + } + /** insert the last constant bit **/ + if(xsConcatenate(&query,start,-1)) goto error; + + /** If you want to do something with all the DB queries + * ** this is the place + * **/ + /* printf("TEST: query=\"%s\"\n",query.String); */ + + if(mysql_query(&conn->Handle,query.String)) goto error; + result = mysql_store_result(&conn->Handle); + err = mysql_errno(&conn->Handle); + if (err) + { + errtxt = (char*)mysql_error(&conn->Handle); + mssError(1,"MYSD","SQL command failed: %s", errtxt); + if (result) mysql_free_result(result); + result = MYSD_RUNQUERY_ERROR; + if (err == 1022 || err == 1061 || err == 1062) + errno = EEXIST; + else + errno = EINVAL; + } + + error: + xsDeInit(&query); + return result; + } + +MYSQL_RES* +mysd_internal_RunQuery_conn(pMysdConn conn, pMysdNode node, char* stmt, ...) + { + MYSQL_RES * result = NULL; + va_list ap; + + va_start(ap,stmt); + result = mysd_internal_RunQuery_conn_va(conn, node, stmt, ap); + va_end(ap); + + return result; + } + +MYSQL_RES* +mysd_internal_RunQuery(pMysdNode node, char* stmt, ...) + { + MYSQL_RES * result = NULL; + pMysdConn conn = NULL; + va_list ap; + + /**start up ap and create query XString **/ + + va_start(ap,stmt); + + if(!(conn = mysd_internal_GetConn(node))) + return NULL; + + result = mysd_internal_RunQuery_conn_va(conn, node, stmt, ap); + + mysd_internal_ReleaseConn(&conn); + + va_end(ap); + + return result; + } + + +/*** mysd_internal_SafeAppend - appends a string on a query + * *** this uses mysql_real_escape_string and requires a connection + * ***/ + +int +mysd_internal_SafeAppend(MYSQL* conn, pXString dst, char* src) + { + char* escaped_src; + int length; + int rval = 0; + length = strlen(src); + + escaped_src = nmMalloc(length*2+1); + mysql_real_escape_string(conn,escaped_src,src,length); + if(xsConcatenate(dst,escaped_src,-1)) rval = -1; + + nmFree(escaped_src,length*2+1); + + return rval; + } + +/*** mysd_internal_CxDataToMySQL() - convert cx data to mysql field values + * ***/ +char* +mysd_internal_CxDataToMySQL(int type, pObjData val) + { + char* tmp; + int length; + int j; + + /** Handle nulls **/ + if (!val) + return NULL; + + /** Convert based on data type **/ + if (type == DATA_T_INTEGER || type == DATA_T_DOUBLE) + { + return objDataToStringTmp(type,val,0); + } + if (type == DATA_T_DATETIME) + { + return (char*)objFormatDateTmp((pDateTime)val,"yyyy-MM-dd HH:mm:ss"); + } + if (type == DATA_T_MONEY) + { + return (char*)objFormatMoneyTmp((pMoneyType)val,"^.####"); + } + if (type == DATA_T_STRING) + { + return objDataToStringTmp(type,val,0); + } + return NULL; + } + +/*** mysd_internal_ParseTData() - given a mysql result set, parse the table + * *** data into a MysdTable structure. Returns < 0 on failure. + * ***/ +int +mysd_internal_ParseTData(MYSQL_RES *resultset, int rowcnt, pMysdTable tdata) + { + int i; + MYSQL_ROW row; + char data_desc[32]; + char* pptr; + char* cptr; + int len; + char* pos; + + if (rowcnt > MYSD_MAX_COLS) + { + mssError(1,"MYSD","Too many columns (%d) in table [%s]", rowcnt, tdata->Name); + return -1; + } + + /** Loop through the result set with the column descriptions **/ + tdata->nCols = tdata->nKeys = 0; + for(i=0;iCols[tdata->nCols] = nmSysStrdup(row[0]); + strtcpy(data_desc, row[1], sizeof(data_desc)); + + /** Length, if char/varchar **/ + tdata->ColLengths[tdata->nCols] = 0; + if ((pptr = strchr(data_desc, '(')) != NULL) + { + *pptr = '\0'; + tdata->ColLengths[tdata->nCols] = strtoui(pptr+1, NULL, 10); + if ((cptr = strchr(pptr+1, ',')) != NULL) + len = strtoi(cptr+1, NULL, 10); + } + + /** set lengths for various text types **/ + if(!strcmp(data_desc, "tinytext") || !strcmp(data_desc, "tinyblob")) tdata->ColLengths[tdata->nCols] = 0xFF; + if(!strcmp(data_desc, "text") || !strcmp(data_desc, "blob")) tdata->ColLengths[tdata->nCols] = 0xFFFF; + if(!strcmp(data_desc, "mediumtext") || !strcmp(data_desc, "mediumblob")) tdata->ColLengths[tdata->nCols] = 0xFFFFFF; + if(!strcmp(data_desc, "longtext") || !strcmp(data_desc, "longblob")) tdata->ColLengths[tdata->nCols] = 0xFFFFFFFF; + + /** Type **/ + tdata->ColTypes[tdata->nCols] = nmSysStrdup(data_desc); + if (!strcmp(data_desc, "int") || !strcmp(data_desc, "bigint") || !strcmp(data_desc, "tinyint") || !strcmp(data_desc, "smallint") || !strcmp(data_desc, "mediumint") || !strcmp(data_desc, "bit")) + tdata->ColCxTypes[tdata->nCols] = DATA_T_INTEGER; + else if (!strcmp(data_desc, "char") || !strcmp(data_desc, "varchar") + || !strcmp(data_desc, "text") || !strcmp(data_desc, "tinytext") || !strcmp(data_desc, "mediumtext") || !strcmp(data_desc, "longtext") + || !strcmp(data_desc, "blob") || !strcmp(data_desc, "tinyblob") || !strcmp(data_desc, "mediumblob") || !strcmp(data_desc, "longblob")) + tdata->ColCxTypes[tdata->nCols] = DATA_T_STRING; + else if (!strcmp(data_desc, "float") || !strcmp(data_desc, "double")) + tdata->ColCxTypes[tdata->nCols] = DATA_T_DOUBLE; + else if (!strcmp(data_desc, "datetime") || !strcmp(data_desc, "date") || !strcmp(data_desc, "timestamp")) + tdata->ColCxTypes[tdata->nCols] = DATA_T_DATETIME; + else if (!strcmp(data_desc, "decimal")) + tdata->ColCxTypes[tdata->nCols] = DATA_T_MONEY; + else + tdata->ColCxTypes[tdata->nCols] = DATA_T_UNAVAILABLE; + + tdata->ColFlags[i] = 0; + /** unsigned? **/ + if(row[1] && (pos = strchr(row[1],'u'))) + { + if(!strcmp(pos,"unsigned")) + tdata->ColFlags[i] |= MYSD_COL_F_UNSIGNED; + } + + /** Allow nulls **/ + if (row[2] && !strcmp(row[2], "YES")) + tdata->ColFlags[i] |= MYSD_COL_F_NULL; + + /** Primary Key **/ + if (row[3] && !strcmp(row[3], "PRI")) + { + if (tdata->nKeys >= MYSD_MAX_KEYS) + { + mssError(1,"MYSD","Too many key fields in table [%s]",tdata->Name); + return -1; + } + tdata->Keys[tdata->nKeys] = tdata->Cols[tdata->nCols]; + tdata->KeyCols[tdata->nKeys] = tdata->nCols; + tdata->ColKeys[tdata->nCols] = tdata->nKeys; + tdata->nKeys++; + tdata->ColFlags[i] |= MYSD_COL_F_PRIKEY; + } + tdata->nCols++; + } + + return 0; + } + +/*** mysd_internal_GetTData() - get a table information structure + * ***/ +pMysdTable +mysd_internal_GetTData(pMysdNode node, char* tablename) + { + MYSQL_RES * result = NULL; + MYSQL_ROW row; + pMysdTable tdata = NULL; + int length; + int rowcnt; + + /** Value cached already? **/ + tdata = (pMysdTable)xhLookup(&node->Tables, tablename); + if (tdata) + return tdata; + + /** sanatize the table name and build the query**/ + length = strlen(tablename); + /** this next bit will break any charset not ASCII **/ + /** throw an error if some joker tries to throw in a backtick **/ + if(strchr(tablename,'`')) goto error; + result = mysd_internal_RunQuery(node, "SHOW COLUMNS FROM `?`",tablename); + if (!result || result == MYSD_RUNQUERY_ERROR) + goto error; + rowcnt = mysql_num_rows(result); + if (rowcnt <= 0) + goto error; + + /** Build the TData **/ + tdata = (pMysdTable)nmMalloc(sizeof(MysdTable)); + if (!tdata) + goto error; + memset(tdata, 0, sizeof(MysdTable)); + strtcpy(tdata->Name, tablename, sizeof(tdata->Name)); + tdata->Node = node; + if (mysd_internal_ParseTData(result, rowcnt, tdata) < 0) + { + nmFree(tdata, sizeof(MysdTable)); + tdata = NULL; + } + + /** Get annotation data **/ + if (result && result != MYSD_RUNQUERY_ERROR) + mysql_free_result(result); + result = mysd_internal_RunQuery(node, "SELECT a,b,c FROM `?` WHERE a = '?'", node->AnnotTable, tablename); + if (result && result != MYSD_RUNQUERY_ERROR) + { + if (mysql_num_rows(result) == 1) + { + row = mysql_fetch_row(result); + if (row) + { + tdata->Annotation = nmSysStrdup((row[1])?(row[1]):""); + tdata->ObjList = expCreateParamList(); + expAddParamToList(tdata->ObjList, NULL, NULL, 0); + tdata->RowAnnotExpr = (pExpression)expCompileExpression((row[2])?(row[2]):"''", tdata->ObjList, MLX_F_ICASE | MLX_F_FILENAMES, 0); + } + } + } + + error: + if (result && result != MYSD_RUNQUERY_ERROR) + mysql_free_result(result); + if(tdata) + { + xhAdd(&(node->Tables),tdata->Name,(char*)tdata); + } + return tdata; + } + + +/*** mysd_internal_DupRow() - duplicate a MYSQL_ROW structure + * ***/ +MYSQL_ROW +mysd_internal_DupRow(MYSQL_ROW row, MYSQL_RES* result) + { + MYSQL_ROW new_row; + int n_fields; + int i; + + n_fields = mysql_num_fields(result); + if (n_fields <= 0) return NULL; + + new_row = nmSysMalloc((n_fields+1) * sizeof(char*)); + if (!new_row) return NULL; + + for(i=0;iResult) /** we haven't executed the query yet **/ + { + result = mysd_internal_RunQuery(data->Node,"SELECT * FROM `?` ?q",data->TData->Name,qy->Clause.String); + if (!result || result == MYSD_RUNQUERY_ERROR) + return -1; + data->Result=result; + } + + filename[0] = 0x00; + if (data->Row) mysd_internal_FreeRow(data->Row); + data->Row = NULL; + + if((data->Row = mysql_fetch_row(data->Result))) + { + data->Row = mysd_internal_DupRow(data->Row, data->Result); + for(i = 0; iTData->nKeys; i++) + { + sprintf(filename,"%s%s|",filename,data->Row[data->TData->KeyCols[i]]); + } + /** kill the trailing pipe **/ + filename[strlen(filename)-1]=0x00; + } + else + { + ret = -1; + } + + return ret; + } + +/*** mysd_internal_GetNextRow() - get a given row from the database + * *** returns number of rows on success and -1 on error + * ***/ + +int +mysd_internal_GetRowByKey(char* key, pMysdData data) + { + MYSQL_RES * result = NULL; + MYSQL_ROW row = NULL; + int i = 0; + int ret = 0; + + if(!(data->TData)) return -1; + + //result = mysd_internal_RunQuery(data->Node,"SELECT * FROM `?` WHERE CONCAT_WS('|',`?a`)='?' LIMIT 0,1",data->TData->Name,data->TData->Keys,NULL,data->TData->nKeys,',',key); + // result = mysd_internal_RunQuery(data->Node, "SELECT * FROM `?` WHERE ?n LIMIT 0,1", + // data->TData->Name, + // data + // ); + // if (!result || result == MYSD_RUNQUERY_ERROR) + // { + // result = NULL; + // ret = -1; + // } + // + // if (data->Row) mysd_internal_FreeRow(data->Row); + // data->Row = NULL; + // + // if(result && (data->Row = mysql_fetch_row(result))) + // { + // data->Row = mysd_internal_DupRow(data->Row, result); + // data->Result=result; + // ret = mysql_num_rows(result); + // } + // else + // { + // if(data->Result) mysql_free_result(data->Result); + // data->Result=NULL; + // ret = 0; + // } + // + // return ret; + // } + // + // + // /*** mysd_internal_RefreshRow - reload a row of data from the DB, for + // *** example after an update is performed, to make sure we have the data + // *** in the object. + // ***/ + // int + // mysd_internal_RefreshRow(pMysdData data) + // { + // char* ptr; + // int rval; + // + // /** Get the object name (primary key) and then retrieve the row again **/ + // ptr = obj_internal_PathPart(data->Obj->Pathname, data->Obj->SubPtr+2, 1); + // rval = mysd_internal_GetRowByKey(ptr, data); + // if (data->Result) mysql_free_result(data->Result); + // data->Result = NULL; + // + // return rval; + // } + // + // + // /*** mysd_internal_BuildAutoname - figures out how to fill in the required + // *** information for an autoname-based row insertion, and populates the + // *** "Objname" field in the MysdData structure accordingly. Looks in the + // *** OXT for a partially (or fully) completed key, and uses an autonumber + // *** type of approach to complete the remainder of the key. Returns nonnegative + // *** on success and with the autoname semaphore held. Returns negative on error + // *** with the autoname semaphore NOT held. On success, the semaphore must be + // *** released after the successful insertion of the new row. + // ***/ + // int + // mysd_internal_BuildAutoname(pMysdData inf, pMysdConn conn, pObjTrxTree oxt) + // { + // pObjTrxTree keys_provided[8]; + // int n_keys_provided = 0; + // int i,j,colid; + // pObjTrxTree find_oxt, attr_oxt; + // pXString sql = NULL; + // char* key_values[8]; + // char* ptr; + // int rval = 0; + // int t; + // MYSQL_RES* result = NULL; + // MYSQL_ROW row = NULL; + // int restype; + // int intval; + // int len; + // + // if (inf->TData->nKeys == 0) return -1; + // for(j=0;jTData->nKeys;j++) key_values[j] = NULL; + // + // /** Snarf the autoname semaphore **/ + // /*syGetSem(inf->TData->AutonameSem, 1, 0);*/ + // + // /** Try to locate provided keys in the OXT, leave NULL if not found. **/ + // for(j=0;jTData->nKeys;j++) + // { + // colid = inf->TData->KeyCols[j]; + // find_oxt=NULL; + // for(i=0;iChildren.nItems;i++) + // { + // attr_oxt = ((pObjTrxTree)(oxt->Children.Items[i])); + // if (attr_oxt->OpType == OXT_OP_SETATTR) + // { + // if (!strcmp(attr_oxt->AttrName,inf->TData->Cols[colid])) + // { + // find_oxt = attr_oxt; + // find_oxt->Status = OXT_S_COMPLETE; + // break; + // } + // } + // } + // if (find_oxt) + // { + // n_keys_provided++; + // keys_provided[j] = find_oxt; + // ptr = mysd_internal_CxDataToMySQL(find_oxt->AttrType, find_oxt->AttrValue); + // /*if (!strcmp(inf->TData->ColTypes[colid],"bit")) + // { + // if (strtoi(ptr,NULL,10)) + // ptr = "1"; + // else + // ptr = "\\0"; + // }*/ + // if (ptr) + // { + // key_values[j] = nmSysStrdup(ptr); + // if (!key_values[j]) + // { + // rval = -ENOMEM; + // goto exit_BuildAutoname; + // } + // } + // } + // } + // + // /** Build the SQL to do the select max()+1 **/ + // sql = (pXString)nmMalloc(sizeof(XString)); + // if (!sql) + // { + // rval = -ENOMEM; + // goto exit_BuildAutoname; + // } + // xsInit(sql); + // for(j=0;jTData->nKeys;j++) + // { + // colid = inf->TData->KeyCols[j]; + // if (!key_values[j]) + // { + // if (inf->TData->ColCxTypes[colid] != DATA_T_INTEGER) + // { + // mssError(1,"MYSD","Non-integer key field '%s' left NULL on autoname create", inf->TData->Cols[colid]); + // rval = -1; + // goto exit_BuildAutoname; + // } + // for(i=0;iTData->nKeys;i++) + // { + // if (key_values[i]) + // { + // if (sql->String[0]) + // xsConcatenate(sql, " AND ", 5); + // else + // xsConcatenate(sql, " WHERE ", 7); + // xsConcatenate(sql, "`", 1); + // mysd_internal_SafeAppend(&conn->Handle, sql, inf->TData->Cols[inf->TData->KeyCols[i]]); + // xsConcatenate(sql, "` = ", 4); + // t = inf->TData->ColCxTypes[inf->TData->KeyCols[i]]; + // if (t == DATA_T_INTEGER || t == DATA_T_DOUBLE || t == DATA_T_MONEY) + // xsConcatenate(sql, key_values[i], -1); + // else + // { + // xsConcatenate(sql, "'", 1); + // mysd_internal_SafeAppend(&conn->Handle, sql, key_values[i]); + // xsConcatenate(sql, "'", 1); + // } + // } + // } + // + // /** Now that sql is built, send to server **/ + // result=mysd_internal_RunQuery_conn(conn, inf->Node, + // "SELECT ifnull(max(`?`),0)+1 FROM `?` ?q", + // inf->TData->Cols[colid], inf->TData->Name, sql->String); + // if (result != MYSD_RUNQUERY_ERROR) + // { + // row = mysql_fetch_row(result); + // if (row && row[0]) + // { + // /** Got a value. **/ + // key_values[j] = nmSysStrdup(row[0]); + // } + // mysql_free_result(result); + // result = NULL; + // } + // else + // { + // mssError(1,"MYSD","Could not obtain next-value information for key '%s' on table '%s'", + // inf->TData->Cols[colid], inf->TData->Name); + // rval = -1; + // goto exit_BuildAutoname; + // } + // } + // } + // + // /** Okay, all keys filled in. Build the autoname. **/ + // inf->Objname[0] = '\0'; + // for(len=j=0;jTData->nKeys;j++) + // { + // if (j) len += 1; /* for | separator */ + // len += strlen(key_values[j]); + // } + // if (len >= sizeof(inf->Objname)) + // { + // mssError(1,"MYSD","Autoname too long!"); + // rval = -1; + // goto exit_BuildAutoname; + // } + // for(j=0;jTData->nKeys;j++) + // { + // if (j) strcat(inf->Objname,"|"); + // strcat(inf->Objname, key_values[j]); + // } + // + // exit_BuildAutoname: + // /** Release resources we used **/ + // if (result && result != MYSD_RUNQUERY_ERROR) + // mysql_free_result(result); + // /*if (rval < 0) + // syPostSem(inf->TData->AutonameSem, 1, 0);*/ + // if (sql) + // { + // xsDeInit(sql); + // nmFree(sql, sizeof(XString)); + // sql = NULL; + // } + // for(j=0;jTData->nKeys;j++) + // if (key_values[j]) nmSysFree(key_values[j]); + // + // return rval; + // } + // + // + // /*** mysd_internal_UpdateRow() - update a given row + // ***/ + // int + // mysd_internal_UpdateRow(pMysdData data, char* newval, int col) + // { + // pMysdConn conn = NULL; + // int i = 0; + // MYSQL_RES* result; + // int use_quotes; + // + // /** Handle bits **/ + // /*if (!strcmp(data->TData->ColTypes[col], "bit") && newval) + // { + // if (strtoi(newval, NULL, 10)) + // newval = "1"; + // else + // newval = "0"; + // }*/ + // + // /** Quote the value if not an integer and value is not NULL **/ + // use_quotes = (data->TData->ColCxTypes[col] != DATA_T_INTEGER && newval != NULL); + // + // //result = mysd_internal_RunQuery(data->Node,"UPDATE `?` SET `?`=?v WHERE CONCAT_WS('|',`?a`)='?'", data->TData->Name, data->TData->Cols[col],newval?newval:"NULL",use_quotes, data->TData->Keys,NULL,data->TData->nKeys,',', data->Name); + // result = mysd_internal_RunQuery(data->Node,"UPDATE `?` SET `?`=?v WHERE ?n", + // data->TData->Name, + // data->TData->Cols[col], + // newval?newval:"NULL", + // use_quotes, + // data + // ); + // if (result == MYSD_RUNQUERY_ERROR) + // return -1; + // + // mysd_internal_RefreshRow(data); + // return 0; + // } + // + // /*** mysd_internal_DeleteRow() - update a given row + // ***/ + // int + // mysd_internal_DeleteRow(pMysdData data) + // { + // pMysdConn conn = NULL; + // int i = 0; + // MYSQL_RES* result; + // + // /** Only rows can be deleted **/ + // if (data->Type != MYSD_T_ROW) return -1; + // + // //result = mysd_internal_RunQuery(data->Node,"DELETE FROM `?` WHERE CONCAT_WS('|',`?a`)='?'",data->TData->Name,data->TData->Keys,NULL,data->TData->nKeys,',', data->Name); + // result = mysd_internal_RunQuery(data->Node,"DELETE FROM `?` WHERE ?n", + // data->TData->Name, + // data + // ); + // if (result == MYSD_RUNQUERY_ERROR) + // return -1; + // return 0; + // } + // + // + // /*** mysd_internal_InsertRow() - update a given row + // ***/ + // int + // mysd_internal_InsertRow(pMysdData inf, pObjTrxTree oxt) + // { + // char* kptr; + // char* find_str; + // char* ptr; + // int i,j,len,ctype,restype; + // int* length; + // pObjTrxTree attr_oxt, find_oxt; + // pXString insbuf = NULL; + // char* values[MYSD_MAX_COLS]; + // char* cols[MYSD_MAX_COLS]; + // char* filename; + // MYSQL_RES* result = MYSD_RUNQUERY_ERROR; + // pMysdConn conn = NULL; + // char namebuf[OBJSYS_MAX_PATH]; + // char* namekeys[MYSD_MAX_KEYS]; + // char use_quotes[MYSD_MAX_COLS]; + // + // /** Allocate a buffer for our insert statement. **/ + // insbuf = (pXString)nmMalloc(sizeof(XString)); + // if (!insbuf) + // goto error; + // xsInit(insbuf); + // + // /** Get a connection. **/ + // conn = mysd_internal_GetConn(inf->Node); + // if (!conn) + // goto error; + // + // /** Auto-naming? **/ + // if ((inf->Obj->Mode & OBJ_O_AUTONAME) && !strcmp(inf->Name, "*")) + // { + // if (mysd_internal_BuildAutoname(inf, conn, oxt) < 0) + // { + // mssError(0, "MYSD", "Could not generate a name for new object."); + // goto error; + // } + // inf->Name = inf->Objname; + // } + // + // /** Make a copy of the object name so we can parse it out **/ + // strtcpy(namebuf, inf->Name, sizeof(namebuf)); + // filename = namebuf; + // + // /** Get our keys array from the name **/ + // memset(namekeys, 0, sizeof(namekeys)); + // for(j=0;jTData->nCols;j++) + // { + // find_oxt = NULL; + // find_str = NULL; + // + // /** Look in the filename **/ + // if (inf->TData->ColFlags[j] & MYSD_COL_F_PRIKEY) + // { + // if (namekeys[inf->TData->ColKeys[j]]) + // find_str = namekeys[inf->TData->ColKeys[j]]; + // } + // + // /** we scan through the OXT's **/ + // for(i=0;iChildren.nItems;i++) + // { + // attr_oxt = ((pObjTrxTree)(oxt->Children.Items[i])); + // if (attr_oxt->OpType == OXT_OP_SETATTR) + // { + // if (!strcmp(attr_oxt->AttrName,inf->TData->Cols[j])) + // { + // find_oxt = attr_oxt; + // find_oxt->Status = OXT_S_COMPLETE; + // break; + // } + // } + // } + // if (j!=0) xsConcatenate(insbuf,"\0",1); + // + // /** Print the appropriate type. **/ + // if (!find_oxt && !find_str) + // { + // if (inf->TData->ColFlags[j] & MYSD_COL_F_NULL) + // { + // /** Mark the field as NULL with a unique value here **/ + // values[j] = (char*)-1; + // } + // else + // { + // mssError(1,"MYSD","Required column '%s' not specified in object create", inf->TData->Cols[j]); + // goto error; + // } + // } + // else + // { + // if ((!find_oxt || !find_oxt->AttrValue) && !find_str) + // { + // if (inf->TData->ColFlags[j] & MYSD_COL_F_NULL) + // { + // /** Mark the field as NULL with a unique value here **/ + // values[j] = (char*)-1; + // } + // else + // { + // mssError(1,"MYSD","Required column '%s' set to NULL in object create", inf->TData->Cols[j]); + // goto error; + // } + // } + // else + // { + // values[j] = (char*)(uintptr_t)insbuf->Length; + // if(!find_str) + // { + // find_str = mysd_internal_CxDataToMySQL(find_oxt->AttrType,find_oxt->AttrValue); + // /*if (!strcmp(inf->TData->ColTypes[j],"bit")) + // { + // if (strtoi(find_str,NULL,10)) + // find_str = "1"; + // else + // find_str = "\\0"; + // }*/ + // } + // if(find_str) + // xsConcatenate(insbuf,find_str,-1); + // else + // { + // mssError(1,"MYSD","Unable to convert data"); + // goto error; + // } + // } + // } + // } + // + // /** Entirely leave NULLs out of the insert **/ + // i = 0; + // for(j=0;jTData->nCols;j++) + // { + // if(values[j] != (char*)-1) + // { + // cols[i] = inf->TData->Cols[j]; + // values[i] = (char*)((uintptr_t)values[j] + (uintptr_t)insbuf->String); + // use_quotes[i] = (inf->TData->ColCxTypes[j] != DATA_T_INTEGER); + // i++; + // } + // } + // + // /** Do the insert **/ + // result = mysd_internal_RunQuery_conn(conn, inf->Node,"INSERT INTO `?` (`?a`) VALUES(?a)",inf->TData->Name,cols,NULL,i,',',values,use_quotes,i,','); + // /*if (result != MYSD_RUNQUERY_ERROR) + // mysd_internal_RefreshRow(inf);*/ + // + // /** clean up **/ + // error: + // if (conn) + // mysd_internal_ReleaseConn(&conn); + // if (insbuf) + // { + // xsDeInit(insbuf); + // nmFree(insbuf,sizeof(XString)); + // } + // + // return (result == MYSD_RUNQUERY_ERROR)?(-1):0; + // } + // + // + // /*** mysd_internal_GetTablenames() - throw the table names in an Xarray + // ***/ + // int + // mysd_internal_GetTablenames(pMysdNode node) + // { + // MYSQL_RES * result = NULL; + // MYSQL_ROW row; + // pMysdConn conn; + // int nTables; + // char* tablename; + // + // result = mysd_internal_RunQuery(node,"SHOW TABLES"); + // if (result == MYSD_RUNQUERY_ERROR || !result) + // return -1; + // + // nTables = mysql_num_rows(result); + // xaInit(&node->Tablenames,nTables); + // + // while((row = mysql_fetch_row(result))) + // { + // if (row[0]) + // { + // tablename = nmSysStrdup((char*)(row[0])); + // if(xaAddItem(&node->Tablenames, tablename) < 0) + // { + // mysql_free_result(result); + // return -1; + // } + // } + // } + // + // mysql_free_result(result); + // return 0; + // } + // + // /*** mysd_internal_OpenNode() - access the node object and get the mysql + // *** server connection parameters. + // ***/ + // pMysdNode + // mysd_internal_OpenNode(char* path, int mode, pObject obj, int node_only, int mask) + // { + // pMysdNode db_node; + // pSnNode sn_node; + // char* ptr = NULL; + // int i; + // + // /** First, do a lookup in the db node cache. **/ + // db_node = (pMysdNode)xhLookup(&(MYSD_INF.DBNodesByPath), path); + // if (db_node) + // { + // db_node->LastAccess = MYSD_INF.AccessCnt; + // MYSD_INF.AccessCnt++; + // return db_node; + // } + // + // /** Mask CREATE if not opening the node itself. **/ + // if (!node_only) + // { + // mode = O_RDONLY; + // } + // + // /** Was the node newly created? **/ + // if ((obj->Prev->Flags & OBJ_F_CREATED) && (mode & O_CREAT)) + // { + // sn_node = snNewNode(obj->Prev, "application/mysql"); + // if (!sn_node) + // { + // mssError(0,"MYSQL","Database node create failed"); + // return NULL; + // } + // snSetParamString(sn_node,obj->Prev,"server","localhost"); + // snSetParamString(sn_node,obj->Prev,"database",""); + // snSetParamString(sn_node,obj->Prev,"annot_table","CXTableAnnotations"); + // snSetParamString(sn_node,obj->Prev,"description","MySQL Database"); + // snSetParamInteger(sn_node,obj->Prev,"max_connections",16); + // snWriteNode(obj->Prev,sn_node); + // } + // else + // { + // sn_node = snReadNode(obj->Prev); + // if (!sn_node) + // { + // mssError(0,"MYSQL","Database node open failed"); + // return NULL; + // } + // } + // + // /** Create the DB node and fill it in. **/ + // db_node = (pMysdNode)nmMalloc(sizeof(MysdNode)); + // if (!db_node) + // { + // mssError(0,"MYSQL","Could not allocate DB node structure"); + // return NULL; + // } + // memset(db_node,0,sizeof(MysdNode)); + // db_node->SnNode = sn_node; + // strtcpy(db_node->Path,path,sizeof(db_node->Path)); + // if (stAttrValue(stLookup(sn_node->Data,"server"),NULL,&ptr,0) < 0) ptr = NULL; + // strtcpy(db_node->Server,ptr?ptr:"localhost",sizeof(db_node->Server)); + // if (stAttrValue(stLookup(sn_node->Data,"database"),NULL,&ptr,0) < 0) ptr = NULL; + // strtcpy(db_node->Database,ptr?ptr:"",sizeof(db_node->Database)); + // if (stAttrValue(stLookup(sn_node->Data,"annot_table"),NULL,&ptr,0) < 0) ptr = NULL; + // strtcpy(db_node->AnnotTable,ptr?ptr:"CXTableAnnotations",sizeof(db_node->AnnotTable)); + // if (stAttrValue(stLookup(sn_node->Data,"description"),NULL,&ptr,0) < 0) ptr = NULL; + // strtcpy(db_node->Description,ptr?ptr:"",sizeof(db_node->Description)); + // if (stAttrValue(stLookup(sn_node->Data,"max_connections"),&i,NULL,0) < 0) i=16; + // if (stAttrValue(stLookup(sn_node->Data,"use_system_auth"),NULL,&ptr,0) == 0) + // { + // if (!strcasecmp(ptr,"yes")) + // db_node->Flags |= MYSD_NODE_F_USECXAUTH; + // } + // if (stAttrValue(stLookup(sn_node->Data,"set_passwords"),NULL,&ptr,0) == 0) + // { + // if (!strcasecmp(ptr,"yes")) + // db_node->Flags |= MYSD_NODE_F_SETCXAUTH; + // } + // if (stAttrValue(stLookup(sn_node->Data,"username"),NULL,&ptr,0) < 0) ptr = "cxguest"; + // strtcpy(db_node->Username,ptr,sizeof(db_node->Username)); + // if (stAttrValue(stLookup(sn_node->Data,"password"),NULL,&ptr,0) < 0) ptr = ""; + // strtcpy(db_node->Password,ptr,sizeof(db_node->Password)); + // if (stAttrValue(stLookup(sn_node->Data,"default_password"),NULL,&ptr,0) < 0) ptr = ""; + // strtcpy(db_node->DefaultPassword,ptr,sizeof(db_node->DefaultPassword)); + // db_node->MaxConn = i; + // xaInit(&(db_node->Conns),16); + // xhInit(&(db_node->Tables),255,0); + // db_node->ConnAccessCnt = 0; + // + // /** Get table names **/ + // if((i=mysd_internal_GetTablenames(db_node)) < 0) + // { + // mssError(0,"MYSD","Unable to query for table names"); + // nmFree(db_node,sizeof(MysdNode)); + // return NULL; + // } + // + // /** Add node to the db node cache **/ + // xhAdd(&(MYSD_INF.DBNodesByPath), db_node->Path, (void*)db_node); + // xaAddItem(&MYSD_INF.DBNodeList, (void*)db_node); + // + // return db_node; + // } + // + // /*** mysd_internal_DetermineType() - determine the object type being opened and + // *** setup the table, row, etc. pointers. + // ***/ + // int + // mysd_internal_DetermineType(pObject obj, pMysdData inf) + // { + // int i; + // + // /** Determine object type (depth) and get pointers set up **/ + // obj_internal_CopyPath(&(inf->Pathname),obj->Pathname); + // for(i=1;iPathname.nElements;i++) *(inf->Pathname.Elements[i]-1) = 0; + // + // /** Set up pointers based on number of elements past the node object **/ + // if (inf->Pathname.nElements == obj->SubPtr) + // { + // inf->Type = MYSD_T_DATABASE; + // obj->SubCnt = 1; + // } + // if (inf->Pathname.nElements - 1 >= obj->SubPtr) + // { + // inf->Type = MYSD_T_TABLE; + // obj->SubCnt = 2; + // } + // if (inf->Pathname.nElements - 2 >= obj->SubPtr) + // { + // if (!strncmp(inf->Pathname.Elements[obj->SubPtr+1],"rows",4)) inf->Type = MYSD_T_ROWSOBJ; + // else if (!strncmp(inf->Pathname.Elements[obj->SubPtr+1],"columns",7)) inf->Type = MYSD_T_COLSOBJ; + // else return -1; + // obj->SubCnt = 3; + // } + // if (inf->Pathname.nElements - 3 >= obj->SubPtr) + // { + // if (inf->Type == MYSD_T_ROWSOBJ) inf->Type = MYSD_T_ROW; + // else if (inf->Type == MYSD_T_COLSOBJ) inf->Type = MYSD_T_COLUMN; + // obj->SubCnt = 4; + // } + // + // /** Point to name. **/ + // strtcpy(inf->Objname, inf->Pathname.Elements[obj->SubPtr + obj->SubCnt - 1 - 1], sizeof(inf->Objname)); + // inf->Name = inf->Objname; + // + // return 0; + // } + // + // /*** mysd_internal_TreeToClause - convert an expression tree to the appropriate + // *** clause for the SQL statement. + // ***/ + // int + // mysd_internal_TreeToClause(pExpression tree, pMysdTable *tdata, pXString where_clause, MYSQL * conn) + // { + // pExpression subtree; + // int i,id = 0; + // XString tmp; + // char* fn_use_name; + // int use_stock_fn_call; + // char quote; + // char* ptr; + // + // /** Check recursion **/ + // if (thExcessiveRecursion()) + // { + // mssError(1,"MYSD","Failed to run query: resource exhaustion occurred"); + // return -1; + // } + // + // xsInit(&tmp); + // + // /** If int or string, just put the content, otherwise recursively build **/ + // switch (tree->NodeType) + // { + // case EXPR_N_DATETIME: + // mysd_DO_DATETIME: + // ptr = objFormatDateTmp(&(tree->Types.Date),"yyyy-MM-dd HH:mm:ss"); + // xsConcatQPrintf(where_clause, "convert(%STR&DQUOT, datetime)", ptr); + // /*objDataToString(where_clause, DATA_T_DATETIME, &(tree->Types.Date), DATA_F_QUOTED);*/ + // break; + // + // case EXPR_N_MONEY: + // mysd_DO_MONEY: + // ptr = objFormatMoneyTmp(&(tree->Types.Money), "0.0000"); + // xsConcatenate(where_clause, ptr, -1); + // /*objDataToString(where_clause, DATA_T_MONEY, &(tree->Types.Money), DATA_F_QUOTED);*/ + // break; + // + // case EXPR_N_DOUBLE: + // mysd_DO_DOUBLE: + // objDataToString(where_clause, DATA_T_DOUBLE, &(tree->Types.Double), DATA_F_QUOTED); + // break; + // + // case EXPR_N_INTEGER: + // mysd_DO_INTEGER: + // if (!tree->Parent || tree->Parent->NodeType == EXPR_N_AND || + // tree->Parent->NodeType == EXPR_N_OR) + // { + // if (tree->Integer) + // xsConcatenate(where_clause, " (1=1) ", 6); + // else + // xsConcatenate(where_clause, " (1=0) ", 7); + // } + // else + // { + // objDataToString(where_clause, DATA_T_INTEGER, &(tree->Integer), DATA_F_QUOTED); + // } + // break; + // + // case EXPR_N_STRING: + // mysd_DO_STRING: + // quote = '\''; + // if (tree->Parent && tree->Parent->NodeType == EXPR_N_FUNCTION && + // (!strcmp(tree->Parent->Name,"convert") || !strcmp(tree->Parent->Name,"datepart")) && + // (void*)tree == (void*)(tree->Parent->Children.Items[0])) + // { + // if (!strcmp(tree->Parent->Name,"convert")) + // { + // quote = ' '; + // if (!strcmp(tree->String,"integer")) xsConcatenate(&tmp,"signed integer",-1); + // else if (!strcmp(tree->String,"string")) + // { + // xsConcatenate(&tmp,"char",-1); + // tree->Parent->DataType = DATA_T_STRING; + // } + // else if (!strcmp(tree->String,"double")) xsConcatenate(&tmp,"double",6); + // else if (!strcmp(tree->String,"money")) xsConcatenate(&tmp,"decimal(14,4)",13); + // else if (!strcmp(tree->String,"datetime")) xsConcatenate(&tmp,"datetime",8); + // } + // else + // { + // if (strpbrk(tree->String,"\"' \t\r\n")) + // { + // mssError(1,"mysd","Invalid datepart() parameters in Expression Tree"); + // } + // else + // { + // objDataToString(&tmp, DATA_T_STRING, tree->String, 0); + // } + // } + // } + // else + // { + // objDataToString(&tmp, DATA_T_STRING, tree->String, 0); + // } + // xsConcatenate(where_clause, "e, 1); + // mysd_internal_SafeAppend(conn,where_clause,tmp.String); + // xsConcatenate(where_clause, "e, 1); + // xsDeInit(&tmp); + // xsInit(&tmp); + // break; + // + // case EXPR_N_OBJECT: + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // break; + // + // case EXPR_N_PROPERTY: + // /** 'Frozen' object? IF so, use current tree value **/ + // if (tree->Flags & EXPR_F_FREEZEEVAL || (tree->Parent && (tree->Parent->Flags & EXPR_F_FREEZEEVAL))) + // { + // if (tree->Flags & EXPR_F_NULL) + // { + // xsConcatenate(where_clause, " NULL ", 6); + // break; + // } + // if (tree->DataType == DATA_T_INTEGER) goto mysd_DO_INTEGER; + // else if (tree->DataType == DATA_T_STRING) goto mysd_DO_STRING; + // else if (tree->DataType == DATA_T_DATETIME) goto mysd_DO_DATETIME; + // else if (tree->DataType == DATA_T_MONEY) goto mysd_DO_MONEY; + // else if (tree->DataType == DATA_T_DOUBLE) goto mysd_DO_DOUBLE; + // } + // + // /** Direct ref object? **/ + // if (tree->ObjID == -1) + // { + // expEvalTree(tree,NULL); + // + // /** Insert NULL, integer, or string, depending on evaluator results **/ + // if (tree->Flags & EXPR_F_NULL) + // { + // xsConcatenate(where_clause, " NULL ", 6); + // } + // else if (tree->DataType == DATA_T_INTEGER) + // { + // objDataToString(where_clause, DATA_T_INTEGER, &(tree->Integer), DATA_F_QUOTED); + // } + // else if (tree->DataType == DATA_T_STRING) + // { + // objDataToString(where_clause, DATA_T_STRING, &(tree->String), DATA_F_QUOTED | DATA_F_SYBQUOTE); + // } + // else if (tree->DataType == DATA_T_DOUBLE) + // { + // objDataToString(where_clause, DATA_T_DOUBLE, &(tree->Types.Double), DATA_F_QUOTED); + // } + // else if (tree->DataType == DATA_T_MONEY) + // { + // objDataToString(where_clause, DATA_T_MONEY, &(tree->Types.Money), DATA_F_QUOTED); + // } + // else if (tree->DataType == DATA_T_DATETIME) + // { + // objDataToString(where_clause, DATA_T_DATETIME, &(tree->Types.Date), DATA_F_QUOTED); + // } + // } + // else + // { + // /** Is this a special type of property (i.e., name or annotation?) **/ + // if (!strcmp(tree->Name,"name")) + // { + // xsConcatenate(where_clause, " CONCAT_WS('|', ", -1); + // for(i=0;inKeys;i++) + // { + // if (i != 0) xsConcatenate(where_clause, " , ", 3); + // xsConcatenate(where_clause, "cast(`", -1); + // mysd_internal_SafeAppend(conn, where_clause, tdata[id]->Keys[i]); + // xsConcatenate(where_clause, "` as char)", 10); + // } + // xsConcatenate(where_clause, ") ",2); + // } + // else if (!strcmp(tree->Name,"annotation")) + // { + // /** no anotation support atm **/ + // } + // else + // { + // /** "Normal" type of object... **/ + // xsConcatenate(where_clause, " `", 2); + // mysd_internal_SafeAppend(conn, where_clause, tree->Name); + // xsConcatenate(where_clause, "` ", 2); + // } + // } + // break; + // + // case EXPR_N_COMPARE: + // xsConcatenate(where_clause, " (", 2); + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, " ", 1); + // if (tree->CompareType & MLX_CMP_LESS) xsConcatenate(where_clause,"<",1); + // if (tree->CompareType & MLX_CMP_GREATER) xsConcatenate(where_clause,">",1); + // if (tree->CompareType & MLX_CMP_EQUALS) xsConcatenate(where_clause,"=",1); + // xsConcatenate(where_clause, " ", 1); + // subtree = (pExpression)(tree->Children.Items[1]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // break; + // + // case EXPR_N_AND: + // xsConcatenate(where_clause, " (",2); + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, " AND ",5); + // subtree = (pExpression)(tree->Children.Items[1]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, ") ",2); + // break; + // + // case EXPR_N_OR: + // xsConcatenate(where_clause, " (",2); + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, " OR ",4); + // subtree = (pExpression)(tree->Children.Items[1]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, ") ",2); + // break; + // + // case EXPR_N_ISNOTNULL: + // xsConcatenate(where_clause, " (",2); + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, " IS NOT NULL) ",14); + // break; + // + // case EXPR_N_ISNULL: + // xsConcatenate(where_clause, " (",2); + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, " IS NULL) ",10); + // break; + // + // case EXPR_N_NOT: + // xsConcatenate(where_clause, " ( NOT ( ",9); + // subtree = (pExpression)(tree->Children.Items[0]); + // mysd_internal_TreeToClause(subtree,tdata,where_clause,conn); + // xsConcatenate(where_clause, " ) ) ",5); + // break; + // + // case EXPR_N_FUNCTION: + // /** Special case functions which MySQL doesn't have. **/ + // fn_use_name = tree->Name; + // use_stock_fn_call = 0; + // if (!strcmp(tree->Name,"condition") && tree->Children.nItems == 3) + // { + // fn_use_name = "if"; + // use_stock_fn_call = 1; + // } + // else if (!strcmp(tree->Name,"isnull")) + // { + // /** MySQL isnull() does something different than CX isnull(). Use ifnull() instead. **/ + // fn_use_name = "ifnull"; + // use_stock_fn_call = 1; + // } + // else if (!strcmp(tree->Name,"convert")) + // { + // /** MySQL convert() params are reversed to what CX, Sybase, and MS SQL expect. **/ + // xsConcatenate(where_clause, " convert(", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " , ", 3); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // } + // else if (!strcmp(tree->Name,"charindex")) + // { + // /** MySQL locate() function is the equivalent of CX charindex() **/ + // fn_use_name = "locate"; + // use_stock_fn_call = 1; + // } + // else if (!strcmp(tree->Name,"getdate")) + // { + // /** MySQL now() function is the equivalent of CX getdate() **/ + // fn_use_name = "now"; + // use_stock_fn_call = 1; + // } + // else if (!strcmp(tree->Name,"user_name")) + // { + // /** MySQL equivalent is substring_index(current_user(),'@',1) **/ + // xsConcatenate(where_clause, " substring_index(current_user(),'@',1) ", -1); + // } + // else if (!strcmp(tree->Name,"datediff")) + // { + // /** MySQL uses timestampdiff() **/ + // subtree = (pExpression)(tree->Children.Items[0]); + // if (subtree->DataType != DATA_T_STRING || subtree->Flags & EXPR_F_NULL) + // { + // mssError(1,"MYSD","Invalid date part for datediff()"); + // return -1; + // } + // if (!strcmp(subtree->String,"day") || !strcmp(subtree->String,"month") || + // !strcmp(subtree->String,"year") || !strcmp(subtree->String, "hour") || + // !strcmp(subtree->String,"minute") || !strcmp(subtree->String, "second")) + // { + // xsConcatenate(where_clause, " timestampdiff(", -1); + // xsConcatenate(where_clause, subtree->String, -1); + // xsConcatenate(where_clause, ", ", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ", ", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[2]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", -1); + // } + // else + // { + // mssError(1,"MYSD","Invalid date part to datediff()"); + // return -1; + // } + // } + // else if (!strcmp(tree->Name,"dateadd")) + // { + // /** MySQL uses date_add(date, interval increment datepart) instead of dateadd(datepart, increment, date) **/ + // xsConcatenate(where_clause, " date_add(", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[2]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ", interval ", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " ", 1); + // subtree = (pExpression)(tree->Children.Items[0]); + // if (subtree->DataType != DATA_T_STRING || subtree->Flags & EXPR_F_NULL) + // { + // mssError(1,"MYSD","Invalid date part to dateadd()"); + // return -1; + // } + // if (!strcmp(subtree->String,"day") || !strcmp(subtree->String,"month") || + // !strcmp(subtree->String,"year") || !strcmp(subtree->String, "hour") || + // !strcmp(subtree->String,"minute") || !strcmp(subtree->String, "second")) + // { + // xsConcatenate(where_clause,subtree->String,-1); + // } + // else + // { + // mssError(1,"MYSD","Invalid date part to dateadd()"); + // return -1; + // } + // xsConcatenate(where_clause, ") ", 2); + // } + // else if (!strcmp(tree->Name,"ralign") && tree->Children.nItems == 2) + // { + // xsConcatenate(where_clause, " substring('", -1); + // for(i=0;i<255 && i<((pExpression)(tree->Children.Items[1]))->Integer;i++) + // xsConcatenate(where_clause, " ", 1); + // xsConcatenate(where_clause, "',1,", 4); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " - char_length(", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ")) ", 3); + // } + // else if (!strcmp(tree->Name,"eval")) + // { + // mssError(1,"MYSD","MySQL does not support eval() CXSQL function"); + // /* just put silly thing as text instead of evaluated */ + // if (tree->Children.nItems == 1) mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // return -1; + // } + // else if (!strcmp(tree->Name,"datepart")) + // { + // /** MySQL uses year(), month(), day(), hour(), minute(), second() **/ + // subtree = (pExpression)(tree->Children.Items[0]); + // if (subtree->DataType == DATA_T_STRING && subtree->String && (!strcmp(subtree->String, "year") || !strcmp(subtree->String, "month") || !strcmp(subtree->String, "day") || !strcmp(subtree->String, "hour") || !strcmp(subtree->String, "minute") || !strcmp(subtree->String, "second"))) + // { + // xsConcatenate(where_clause, " ", 1); + // xsConcatenate(where_clause, subtree->String, -1); + // xsConcatenate(where_clause, "(", 1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // } + // else if (subtree->DataType == DATA_T_STRING && subtree->String && (!strcmp(subtree->String, "weekday"))) + // { + // xsConcatenate(where_clause, " dayofweek(", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // } + // else + // { + // mssError(1,"MYSD","Invalid date part for datepart()"); + // return -1; + // } + // } + // else if (!strcmp(tree->Name, "replace")) + // { + // xsConcatenate(where_clause, " replace(", -1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause, conn); + // xsConcatenate(where_clause, ",", 1); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause, conn); + // xsConcatenate(where_clause, ",", 1); + // subtree = (pExpression)tree->Children.Items[2]; + // + // /** MySQL does not accept NULL for the replacement, use "" instead **/ + // if (subtree && (subtree->Flags & EXPR_F_NULL)) + // xsConcatenate(where_clause, "\"\") ", 4); + // else + // { + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[2]), tdata, where_clause, conn); + // xsConcatenate(where_clause, ") ", 2); + // } + // } + // else if (!strcmp(tree->Name, "hash")) + // { + // /** MySQL uses MD5(), SHA1(), SHA2(data, bitsize) **/ + // subtree = (pExpression)(tree->Children.Items[0]); + // if (subtree->DataType == DATA_T_STRING && subtree->String && (!strcmp(subtree->String, "md5") || !strcmp(subtree->String, "sha1") || !strcmp(subtree->String, "sha256") || !strcmp(subtree->String, "sha384") || !strcmp(subtree->String, "sha512"))) + // { + // /** Function call itself **/ + // if (!strcmp(subtree->String, "md5")) + // xsConcatenate(where_clause, " MD5(", 5); + // else if (!strcmp(subtree->String, "sha1")) + // xsConcatenate(where_clause, " SHA1(", 6); + // else if (!strcmp(subtree->String, "sha256") || !strcmp(subtree->String, "sha384") || !strcmp(subtree->String, "sha512")) + // xsConcatenate(where_clause, " SHA2(", 6); + // + // /** Data **/ + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause, conn); + // + // /** Bit length, if needed **/ + // if (!strcmp(subtree->String, "sha256") || !strcmp(subtree->String, "sha384") || !strcmp(subtree->String, "sha512")) + // { + // xsConcatQPrintf(where_clause, ", %POS", strtoi(subtree->String+3, NULL, 10)); + // } + // xsConcatenate(where_clause, ") ", 2); + // } + // else + // { + // mssError(1,"MYSD","Invalid algorithm for hash()"); + // return -1; + // } + // } + // else + // { + // use_stock_fn_call = 1; + // } + // + // if (use_stock_fn_call) + // { + // xsConcatenate(where_clause, " ", 1); + // xsConcatenate(where_clause, fn_use_name, -1); + // xsConcatenate(where_clause, "(", 1); + // for(i=0;iChildren.nItems;i++) + // { + // if (i != 0) xsConcatenate(where_clause,",",1); + // subtree = (pExpression)(tree->Children.Items[i]); + // mysd_internal_TreeToClause(subtree, tdata, where_clause,conn); + // } + // xsConcatenate(where_clause, ") ", 2); + // } + // break; + // + // case EXPR_N_PLUS: + // /** This is a toughie. In Centrallix and Sybase/MSSQL, the + operator + // ** can be used for addition or for string concatenation, and so the + // ** behavior depends on the run-time type of the operands. In MySQL + // ** we have to make this decision in advance, and use CONCAT() for + // ** strings and + for numbers. + // ** + // ** If we know the type of operand 1 in advance, we choose + or CONCAT() + // ** statically. Otherwise, we just have to punt... + // **/ + // if (tree->Children.nItems < 2) + // { + // mssError(1,"MYSD","Insufficient arguments to + operator"); + // return -1; + // } + // subtree = (pExpression)tree->Children.Items[0]; + // if (subtree->NodeType == EXPR_N_PROPERTY && !(subtree->Flags & EXPR_F_FREEZEEVAL) && subtree->DataType == DATA_T_UNAVAILABLE) + // { + // /** A property under our control **/ + // for(i=0;inCols;i++) + // { + // if (!strcmp(subtree->Name, tdata[0]->Cols[i])) + // { + // if (tdata[0]->ColCxTypes[i] == DATA_T_STRING) + // subtree->DataType = DATA_T_STRING; + // } + // } + // } + // if (tree->Parent && tree->Parent->NodeType == EXPR_N_PLUS && tree->Parent->DataType == DATA_T_STRING) + // { + // /** We're within a string concatenation expression already... **/ + // subtree->DataType = DATA_T_STRING; + // } + // if (subtree->NodeType == EXPR_N_FUNCTION && (!strcmp(subtree->Name, "user_name") || !strcmp(subtree->Name, "substring") || !strcmp(subtree->Name, "right"))) + // { + // /** These functions always invariably return a string... **/ + // subtree->DataType = DATA_T_STRING; + // } + // if (subtree->NodeType == EXPR_N_FUNCTION && (!strcmp(subtree->Name, "charindex"))) + // { + // /** These functions always invariably return an integer... **/ + // subtree->DataType = DATA_T_INTEGER; + // } + // if (subtree->NodeType == EXPR_N_FUNCTION && (!strcmp(subtree->Name, "sin") || !strcmp(subtree->Name, "cos") || !strcmp(subtree->Name, "power") || !strcmp(subtree->Name, "sqrt") || !strcmp(subtree->Name, "atan2") || !strcmp(subtree->Name, "radians"))) + // { + // /** These functions always invariably return a floating point type **/ + // subtree->DataType = DATA_T_DOUBLE; + // } + // if (subtree->DataType == DATA_T_STRING) + // { + // /** We get here if 1) op 1 is a constant STRING, 2) op 1 is one of + // ** of our properties and we know it is a string, 3) the parent + // ** node of this + operator is another + operator and it used CONCAT, + // ** or 4) op 1 is a function call that is known to return a string. + // **/ + // tree->DataType = DATA_T_STRING; + // xsConcatenate(where_clause, " CONCAT(", -1); + // mysd_internal_TreeToClause(subtree, tdata, where_clause,conn); + // xsConcatenate(where_clause, " , ", 3); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // } + // else + // { + // /** Let's leave room to change this into a CONCAT if after building + // ** the first subexpression we find out that it is a string. After all, + // ** this needs to work, but it doesn't need to look pretty. + // **/ + // i = strlen(where_clause->String); + // xsConcatenate(where_clause, " (", -1); + // mysd_internal_TreeToClause(subtree, tdata, where_clause,conn); + // if (subtree->DataType == DATA_T_STRING) + // { + // tree->DataType = DATA_T_STRING; + // xsSubst(where_clause, i+1, 6, "CONCAT", 6); + // xsConcatenate(where_clause, " , ", 3); + // } + // else + // { + // xsConcatenate(where_clause, " + ", 3); + // } + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // } + // break; + // + // case EXPR_N_MINUS: + // xsConcatenate(where_clause, " (", 2); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " - ", 3); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // break; + // + // case EXPR_N_DIVIDE: + // xsConcatenate(where_clause, " (", 2); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " / ", 3); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // break; + // + // case EXPR_N_MULTIPLY: + // xsConcatenate(where_clause, " (", 2); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " * ", 3); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[1]), tdata, where_clause,conn); + // xsConcatenate(where_clause, ") ", 2); + // break; + // + // case EXPR_N_IN: + // xsConcatenate(where_clause, " (", 2); + // mysd_internal_TreeToClause((pExpression)(tree->Children.Items[0]), tdata, where_clause,conn); + // xsConcatenate(where_clause, " IN (", 5); + // subtree = (pExpression)(tree->Children.Items[1]); + // if (subtree->NodeType == EXPR_N_LIST) + // { + // for(i=0;iChildren.nItems;i++) + // { + // if (i != 0) xsConcatenate(where_clause, ",", 1); + // mysd_internal_TreeToClause((pExpression)(subtree->Children.Items[i]), tdata, where_clause,conn); + // } + // } + // else + // { + // mysd_internal_TreeToClause(subtree, tdata, where_clause,conn); + // } + // xsConcatenate(where_clause, ") ) ", 4); + // break; + // } + // + // if (tree->Flags & EXPR_F_DESC) xsConcatenate(where_clause, " DESC ", 6); + // + // return 0; + // } + // + // /*** mysdOpen() - open an object. + // ***/ + // void* + // mysdOpen(pObject obj, int mask, pContentType systype, char* usrtype, pObjTrxTree* oxt) + // { + // pMysdData inf; + // int rval; + // int length; + // char* tablename; + // char* node_path; + // char* table; + // char* ptr; + // + // /** Allocate the structure **/ + // inf = (pMysdData)nmMalloc(sizeof(MysdData)); + // if (!inf) return NULL; + // memset(inf,0,sizeof(MysdData)); + // inf->Obj = obj; + // inf->Mask = mask; + // inf->Result = NULL; + // inf->Row = NULL; + // + // /** Determine the type **/ + // if(mysd_internal_DetermineType(obj,inf)) + // { + // mssError(1,"MYSD","Unable to determine type."); + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // + // /** Determine the node path **/ + // node_path = obj_internal_PathPart(obj->Pathname, 0, obj->SubPtr); + // + // /** this leaks memory MUST FIX **/ + // if(!(inf->Node = mysd_internal_OpenNode(node_path, obj->Mode, obj, inf->Type == MYSD_T_DATABASE, inf->Mask))) + // { + // mssError(0,"MYSD","Couldn't open node."); + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // + // /** get table name from path **/ + // if(obj->SubCnt > 1) + // { + // tablename = obj_internal_PathPart(obj->Pathname, obj->SubPtr, 1); + // length = obj->Pathname->Elements[obj->Pathname->nElements - 1] - obj->Pathname->Elements[obj->Pathname->nElements - 2]; + // if(!(inf->TData = mysd_internal_GetTData(inf->Node,tablename))) + // { + // if(obj->Mode & O_CREAT) + // /** Table creation code could some day go here, + // ** but it is not supported right now + // **/ + // mssError(1,"MYSD","Table creation is not supported currently"); + // else + // mssError(1,"MYSD","Table object does not exist."); + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // } + // + // /** Set object params. **/ + // obj_internal_CopyPath(&(inf->Pathname),obj->Pathname); + // inf->Node->SnNode->OpenCnt++; + // + // if(inf->Type == MYSD_T_ROW) + // { + // rval = 0; + // /** Autonaming a new object? Won't be able to look it up if so. **/ + // if (!(inf->Obj->Mode & OBJ_O_AUTONAME)) + // { + // ptr = obj_internal_PathPart(obj->Pathname, obj->SubPtr+2, 1); + // if ((rval = mysd_internal_GetRowByKey(ptr,inf)) < 0) + // { + // mssError(1,"MYSD","Unable to fetch row by key."); + // if(inf->Result) mysql_free_result(inf->Result); + // inf->Result = NULL; + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // else + // { + // if(inf->Result) mysql_free_result(inf->Result); + // inf->Result = NULL; + // } + // } + // if (rval == 0) + // { + // /** User specified a row that doesn't exist. **/ + // if (!(obj->Mode & O_CREAT)) + // { + // mssError(1,"MYSD","Row object does not exist."); + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // + // /** row insert. set up the transaction **/ + // if (!*oxt) *oxt = obj_internal_AllocTree(); + // (*oxt)->OpType = OXT_OP_CREATE; + // (*oxt)->LLParam = (void*)inf; + // (*oxt)->Object = obj; + // (*oxt)->Status = OXT_S_VISITED; + // return inf; + // } + // } + // + // return (void*)inf; + // } + // + // + // /*** mysdClose() - close an open object. + // ***/ + // int + // mysdClose(void* inf_v, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // + // /** commit changes before we get rid of the transaction **/ + // mysdCommit(inf,oxt); + // + // /** Write the node first, if need be. **/ + // snWriteNode(inf->Obj->Prev, inf->Node->SnNode); + // + // /** Release the memory **/ + // inf->Node->SnNode->OpenCnt --; + // obj_internal_FreePathStruct(&inf->Pathname); + // if (inf->Row) mysd_internal_FreeRow(inf->Row); + // inf->Row = NULL; + // nmFree(inf,sizeof(MysdData)); + // + // return 0; + // } + // + // + // /*** mysdCreate() - create a new object, without actually returning a + // *** descriptor for it. For most drivers, it is safe to just call + // *** the Open method with create/exclude set, and then close the + // *** object immediately. + // ***/ + // int + // mysdCreate(pObject obj, int mask, pContentType systype, char* usrtype, pObjTrxTree* oxt) + // { + // int fd; + // void* inf; + // + // /** Call open() then close() **/ + // obj->Mode = O_CREAT | O_EXCL; + // inf = mysdOpen(obj, mask, systype, usrtype, oxt); + // if (!inf) return -1; + // mysdClose(inf, oxt); + // + // return 0; + // } + // + // + // /*** mysdDelete() - delete an existing object. For most drivers, it works to + // *** call open() first to make sure the thing exists and get information + // *** on it, and then "handle the close a bit differently" :) + // ***/ + // int + // mysdDelete(pObject obj, pObjTrxTree* oxt) + // { + // struct stat fileinfo; + // pMysdData inf, find_inf, search_inf; + // int is_empty = 1; + // int i; + // + // /** Open the thing first to get the inf ptrs **/ + // obj->Mode = O_WRONLY; + // inf = (pMysdData)mysdOpen(obj, 0, NULL, "", oxt); + // if (!inf) return -1; + // + // if (inf->Type != MYSD_T_ROW) + // { + // nmFree(inf,sizeof(MysdData)); + // mssError(1,"MYSD","Unimplemented delete operation in MYSD"); + // return -1; + // } + // + // /** delete the row from the DB **/ + // if(!mysd_internal_DeleteRow(inf)) return -1; + // + // /** Physically delete the node, and then remove it from the node cache **/ + // if (inf->Type == MYSD_T_DATABASE) + // unlink(inf->Node->SnNode->NodePath); + // + // /** Release, don't call close because that might write data to a deleted object **/ + // inf->Node->SnNode->OpenCnt --; + // obj_internal_FreePathStruct(&inf->Pathname); + // if (inf->Row) mysd_internal_FreeRow(inf->Row); + // inf->Row = NULL; + // nmFree(inf,sizeof(MysdData)); + // + // return 0; + // } + // + // + // /*** mysdDeleteObj() - delete an already-open object. + // ***/ + // int + // mysdDeleteObj(void* inf_v, pObjTrxTree* oxt) + // { + // pMysdData inf = (pMysdData)inf_v; + // int rval = 0; + // + // /** Delete it. **/ + // if (inf->Type == MYSD_T_ROW) + // { + // /** Ok, can delete rows **/ + // if (!mysd_internal_DeleteRow(inf)) + // rval = -1; + // } + // else + // { + // /** Unimplemented delete **/ + // mssError(1,"MYSD","Unimplemented delete operation in MYSD"); + // rval = -1; + // } + // + // /** Release, don't call close because that might write data to a deleted object **/ + // inf->Node->SnNode->OpenCnt --; + // obj_internal_FreePathStruct(&inf->Pathname); + // if (inf->Row) mysd_internal_FreeRow(inf->Row); + // inf->Row = NULL; + // nmFree(inf,sizeof(MysdData)); + // + // return rval; + // } + // + // + // /*** mysdRead() - Structure elements have no content. Fails. + // ***/ + // int + // mysdRead(void* inf_v, char* buffer, int maxcnt, int offset, int flags, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // return -1; + // } + // + // + // /*** mysdWrite() - Again, no content. This fails. + // ***/ + // int + // mysdWrite(void* inf_v, char* buffer, int cnt, int offset, int flags, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // return -1; + // } + // + // + // /*** mysdOpenQuery() - open a directory query. This driver is pretty + // *** unintelligent about queries. So, we leave the query matching logic + // *** to the ObjectSystem management layer in this case. + // ***/ + // void* + // mysdOpenQuery(void* inf_v, pObjQuery query, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // pMysdQuery qy; + // pMysdConn escape_conn = NULL; + // int i; + // /** check if we should really allow a query **/ + // if(inf->Type==MYSD_T_ROW) return 0; + // if(inf->Type==MYSD_T_COLUMN) return 0; + // + // /** Allocate the query structure **/ + // qy = (pMysdQuery)nmMalloc(sizeof(MysdQuery)); + // if (!qy) return NULL; + // memset(qy, 0, sizeof(MysdQuery)); + // qy->Data = inf; + // if(qy->Data->Result) mysql_free_result(qy->Data->Result); + // qy->Data->Result = NULL; + // qy->ItemCnt = 0; + // qy->Data->Result = NULL; + // xsInit(&qy->Clause); + // + // if(inf->Type==MYSD_T_ROWSOBJ) + // { + // query->Flags |= OBJ_QY_F_FULLQUERY; + // query->Flags |= OBJ_QY_F_FULLSORT; + // if(query->Tree || query->SortBy[0]) + // { + // escape_conn = mysd_internal_GetConn(qy->Data->Node); + // if (!escape_conn) + // return NULL; + // if (query->Tree) + // { + // xsConcatenate(&qy->Clause, " WHERE ", 7); + // mysd_internal_TreeToClause((pExpression)(query->Tree),&(qy->Data->TData),&qy->Clause,&escape_conn->Handle); + // } + // if (query->SortBy[0]) + // { + // xsConcatenate(&qy->Clause," ORDER BY ", 10); + // for(i=0;query->SortBy[i] && i < (sizeof(query->SortBy)/sizeof(void*));i++) + // { + // if (i != 0) xsConcatenate(&qy->Clause, ", ", 2); + // mysd_internal_TreeToClause((pExpression)(query->SortBy[i]),&(qy->Data->TData),&qy->Clause,&escape_conn->Handle); + // } + // } + // mysd_internal_ReleaseConn(&escape_conn); + // } + // } + // else + // { + // query->Flags &= ~OBJ_QY_F_FULLQUERY; + // query->Flags &= ~OBJ_QY_F_FULLSORT; + // } + // + // return (void*)qy; + // } + // + // /*** mysdQueryFetch() - get the next directory entry as an open object. + // ***/ + // void* + // mysdQueryFetch(void* qy_v, pObject obj, int mode, pObjTrxTree* oxt) + // { + // pMysdQuery qy = ((pMysdQuery)(qy_v)); + // pMysdData inf = NULL; + // MYSQL_RES * result = NULL; + // pMysdConn conn; + // char name_buf[(MYSD_NAME_LEN+1)*MYSD_MAX_KEYS]; + // char* new_obj_name = NULL; + // + // /** Alloc the structure **/ + // if(!(inf = (pMysdData)nmMalloc(sizeof(MysdData)))) return NULL; + // memset(inf, 0, sizeof(MysdData)); + // inf->Pathname.OpenCtlBuf = NULL; + // inf->Row = NULL; + // inf->Result = NULL; + // + // /** Get the next name based on the query type. **/ + // switch(qy->Data->Type) + // { + // case MYSD_T_DATABASE: + // if(qy->ItemCnt < qy->Data->Node->Tablenames.nItems) + // { + // inf->Type = MYSD_T_TABLE; + // new_obj_name = qy->Data->Node->Tablenames.Items[qy->ItemCnt]; + // inf->TData = mysd_internal_GetTData(qy->Data->Node, new_obj_name); + // } + // else + // { + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // /** Get filename from the first column - table name. **/ + // break; + // + // case MYSD_T_TABLE: + // /** Filename is either "rows" or "columns" **/ + // if (qy->ItemCnt == 0) + // { + // new_obj_name = "columns"; + // inf->Type = MYSD_T_COLSOBJ; + // } + // else if (qy->ItemCnt == 1) + // { + // new_obj_name = "rows"; + // inf->Type = MYSD_T_ROWSOBJ; + // } + // else + // { + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // break; + // + // case MYSD_T_ROWSOBJ: + // /** Get the rows **/ + // if (!(mysd_internal_GetNextRow(name_buf,qy,qy->Data,qy->Data->TData->Name))) + // { + // inf->Type = MYSD_T_ROW; + // inf->Row = qy->Data->Row; + // qy->Data->Row = NULL; + // /*inf->Result = qy->Data->Result;*/ + // inf->Result = NULL; + // new_obj_name = name_buf; + // } + // else + // { + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // break; + // + // case MYSD_T_COLSOBJ: + // /** return columns until they are all exhausted **/ + // if(!(qy->Data->TData = mysd_internal_GetTData(qy->Data->Node,qy->Data->TData->Name))) + // { + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // if (qy->ItemCnt < qy->Data->TData->nCols) + // { + // inf->Type = MYSD_T_COLUMN; + // new_obj_name = qy->Data->TData->Cols[qy->ItemCnt]; + // } + // else + // { + // nmFree(inf,sizeof(MysdData)); + // return NULL; + // } + // break; + // + // } + // + // /** Build the filename. **/ + // if (obj_internal_AddToPath(obj->Pathname, new_obj_name) < 0) + // return NULL; + // #if 0 + // if (strlen(new_obj_name) > 255) + // { + // mssError(1,"MYSQL","Query result pathname exceeds internal representation"); + // return NULL; + // } + // /** Set up a new element at the end of the pathname **/ + // obj->Pathname->Elements[obj->Pathname->nElements] = obj->Pathname->Pathbuf + strlen(obj->Pathname->Pathbuf); + // obj->Pathname->nElements++; + // sprintf(obj->Pathname->Pathbuf,"%s\%s",qy->Data->Obj->Pathname->Pathbuf,new_obj_name); + // #endif + // + // obj_internal_CopyPath(&(inf->Pathname), obj->Pathname); + // strtcpy(inf->Objname, inf->Pathname.Elements[inf->Pathname.nElements - 1], sizeof(inf->Objname)); + // inf->Name = inf->Objname; + // if (!inf->TData) + // inf->TData = qy->Data->TData; + // inf->Node = qy->Data->Node; + // inf->Node->SnNode->OpenCnt++; + // inf->Obj = obj; + // qy->ItemCnt++; + // + // return (void*)inf; + // } + // + // + // /*** mysdQueryDelete() - delete objects matching the query + // ***/ + // int + // mysdQueryDelete(void* qy_v, pObjTrxTree* oxt) + // { + // pMysdQuery qy = (pMysdQuery)qy_v; + // MYSQL_RES * result; + // + // /** Run the delete. **/ + // result = mysd_internal_RunQuery(qy->Data->Node, "DELETE FROM `?` ?q", qy->Data->TData->Name, qy->Clause.String); + // if (result == MYSD_RUNQUERY_ERROR) + // return -1; + // + // return 0; + // } + // + // + // /*** mysdQueryClose() - close the query. + // ***/ + // int + // mysdQueryClose(void* qy_v, pObjTrxTree* oxt) + // { + // pMysdQuery qy = (pMysdQuery)qy_v; + // static MYSQL_RES * last_result = NULL; + // + // /** Free the last result and store the pointer to this query's result **/ + // if(last_result) mysql_free_result(last_result); + // last_result = qy->Data->Result; + // qy->Data->Result = NULL; + // + // /** Free the structure **/ + // nmFree(qy_v,sizeof(MysdQuery)); + // + // return 0; + // } + // + // + // /*** mysdGetAttrType() - get the type of an attribute by name. + // ***/ + // int + // mysdGetAttrType(void* inf_v, char* attrname, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // int i; + // pStructInf find_inf; + // + // /** If name, it's a string **/ + // if (!strcmp(attrname,"name")) return DATA_T_STRING; + // + // /** If 'content-type', it's also a string. **/ + // if (!strcmp(attrname,"content_type")) return DATA_T_STRING; + // if (!strcmp(attrname,"outer_type")) return DATA_T_STRING; + // if (!strcmp(attrname,"inner_type")) return DATA_T_STRING; + // if (!strcmp(attrname,"annotation")) return DATA_T_STRING; + // + // /** Check for attributes in the node object if that was opened **/ + // if (inf->Obj->Pathname->nElements == inf->Obj->SubPtr) + // { + // } + // + // /** Attr type depends on object type. **/ + // if (inf->Type == MYSD_T_ROW) + // { + // for(i=0;iTData->nCols;i++) + // { + // if (!strcmp(attrname,inf->TData->Cols[i])) + // { + // return(inf->TData->ColCxTypes[i]); + // } + // } + // } + // else if (inf->Type == MYSD_T_COLUMN) + // { + // if (!strcmp(attrname,"datatype")) return DATA_T_STRING; + // } + // + // return -1; + // } + // + // + // /*** mysdGetAttrValue() - get the value of an attribute by name. The 'val' + // *** pointer must point to an appropriate data type. + // ***/ + // int + // mysdGetAttrValue(void* inf_v, char* attrname, int datatype, pObjData val, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // pStructInf find_inf; + // char* ptr; + // int i; + // int ret = 1; + // if (!strcmp(attrname,"name")) + // { + // val->String = inf->Name; + // return 0; + // } + // + // if (!strcmp(attrname,"content_type") || !strcmp(attrname,"inner_type")) + // { + // switch(inf->Type) + // { + // case MYSD_T_DATABASE: val->String = "system/void"; break; + // case MYSD_T_TABLE: val->String = "system/void"; break; + // case MYSD_T_ROWSOBJ: val->String = "system/void"; break; + // case MYSD_T_COLSOBJ: val->String = "system/void"; break; + // case MYSD_T_ROW: val->String = "application/octet-stream"; break; + // case MYSD_T_COLUMN: val->String = "system/void"; break; + // } + // return 0; + // } + // + // if (!strcmp(attrname,"outer_type")) + // { + // switch(inf->Type) + // { + // case MYSD_T_DATABASE: val->String = "application/mysql"; break; + // case MYSD_T_TABLE: val->String = "system/table"; break; + // case MYSD_T_ROWSOBJ: val->String = "system/table-rows"; break; + // case MYSD_T_COLSOBJ: val->String = "system/table-columns"; break; + // case MYSD_T_ROW: val->String = "system/row"; break; + // case MYSD_T_COLUMN: val->String = "system/column"; break; + // } + // return 0; + // } + // + // if (!strcmp(attrname,"annotation")) + // { + // if (datatype != DATA_T_STRING) + // { + // mssError(1,"MYSD","Type mismatch accessing attribute '%s' (should be string)", attrname); + // return -1; + // } + // /** Different for various objects. **/ + // switch(inf->Type) + // { + // case MYSD_T_DATABASE: + // val->String = inf->Node->Description; + // break; + // case MYSD_T_TABLE: + // val->String = (inf->TData->Annotation)?(inf->TData->Annotation):""; + // break; + // case MYSD_T_ROWSOBJ: + // val->String = "Contains rows for this table"; + // break; + // case MYSD_T_COLSOBJ: + // val->String = "Contains columns for this table"; + // break; + // case MYSD_T_COLUMN: + // val->String = "Column within this table"; + // break; + // case MYSD_T_ROW: + // if (!inf->TData->RowAnnotExpr) + // { + // val->String = ""; + // break; + // } + // expModifyParam(inf->TData->ObjList, NULL, inf->Obj); + // inf->TData->ObjList->Session = inf->Obj->Session; + // expEvalTree(inf->TData->RowAnnotExpr, inf->TData->ObjList); + // if (inf->TData->RowAnnotExpr->Flags & EXPR_F_NULL || + // inf->TData->RowAnnotExpr->String == NULL) + // { + // val->String = ""; + // } + // else + // { + // val->String = inf->TData->RowAnnotExpr->String; + // } + // break; + // } + // return 0; + // } + // + // if (!strcmp(attrname,"last_modification")) + // { + // val->String = NULL; + // return 1; + // } + // + // + // /** Column object? Type is the only one. **/ + // if (inf->Type == MYSD_T_COLUMN) + // { + // if (strcmp(attrname,"datatype")) return -1; + // if (datatype != DATA_T_STRING) + // { + // mssError(1,"MYSD","Type mismatch accessing attribute '%s' (should be string)", attrname); + // return -1; + // } + // + // + // /** Search table info for this column. **/ + // for(i=0;iTData->nCols;i++) if (!strcmp(inf->TData->Cols[i], inf->Name)) + // { + // val->String = inf->TData->ColTypes[i]; + // return 0; + // } + // } + // + // else if (inf->Type == MYSD_T_ROW) + // { + // for(i=0;iTData->nCols;i++) if (!strcmp(inf->TData->Cols[i],attrname)) + // { + // if(!inf->Row || !inf->Row[i]) + // { + // return 1; + // } + // else + // { + // switch(inf->TData->ColCxTypes[i]) + // { + // case DATA_T_STRING: + // val->String=inf->Row[i]; + // ret=0; + // break; + // case DATA_T_DATETIME: + // val->DateTime=&(inf->Types.Date); + // objDataToDateTime(DATA_T_STRING, inf->Row[i], val->DateTime, "ISO"); + // ret=0; + // break; + // case DATA_T_MONEY: + // val->Money = &(inf->Types.Money); + // objDataToMoney(DATA_T_STRING, inf->Row[i], val->Money); + // ret=0; + // break; + // case DATA_T_INTEGER: + // if (!strcmp(inf->TData->ColTypes[i], "bit")) + // { + // if (inf->Row[i][0] == 0x01 || inf->Row[i][0] == '1') + // val->Integer = 1; + // else + // val->Integer = 0; + // } + // else + // { + // val->Integer=objDataToInteger(DATA_T_STRING, inf->Row[i], NULL); + // } + // ret=0; + // break; + // case DATA_T_DOUBLE: + // val->Double = objDataToDouble(DATA_T_STRING, inf->Row[i]); + // ret=0; + // break; + // } + // } + // } + // return ret; + // } + // + // + // mssError(1,"MYSD","Could not locate requested attribute"); + // + // return -1; + // } + // + // + // /*** mysdGetNextAttr() - get the next attribute name for this object. + // ***/ + // char* + // mysdGetNextAttr(void* inf_v, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // + // /** Attribute listings depend on object type. **/ + // switch(inf->Type) + // { + // case MYSD_T_DATABASE: + // return NULL; + // + // case MYSD_T_TABLE: + // return NULL; + // + // case MYSD_T_ROWSOBJ: + // return NULL; + // + // case MYSD_T_COLSOBJ: + // return NULL; + // + // case MYSD_T_COLUMN: + // /** only attr is 'datatype' **/ + // if (inf->CurAttr++ == 0) return "datatype"; + // break; + // + // case MYSD_T_ROW: + // /** Return attr in table inf **/ + // if (inf->CurAttr < inf->TData->nCols) return inf->TData->Cols[inf->CurAttr++]; + // break; + // } + // + // return NULL; + // } + // + // + // /*** mysdGetFirstAttr() - get the first attribute name for this object. + // ***/ + // char* + // mysdGetFirstAttr(void* inf_v, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // char* ptr; + // /** Set the current attribute. **/ + // inf->CurAttr = 0; + // + // /** Return the next one. **/ + // ptr = mysdGetNextAttr(inf_v, oxt); + // + // return ptr; + // } + // + // + // /*** mysdSetAttrValue() - sets the value of an attribute. 'val' must + // *** point to an appropriate data type. + // ***/ + // int + // mysdSetAttrValue(void* inf_v, char* attrname, int datatype, pObjData val, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // pStructInf find_inf; + // const int max_money_length = 64; + // char* tmp; + // int length; + // int i,j; + // int type; + // type = mysdGetAttrType(inf, attrname, oxt); + // /** Choose the attr name **/ + // /** Changing name of node object? **/ + // if (!strcmp(attrname,"name")) + // { + // if (inf->Obj->Pathname->nElements == inf->Obj->SubPtr) + // { + // if (!strcmp(inf->Obj->Pathname->Pathbuf,".")) return -1; + // if (strlen(inf->Obj->Pathname->Pathbuf) - + // strlen(strrchr(inf->Obj->Pathname->Pathbuf,'/')) + + // strlen(val->String) + 1 > 255) + // { + // mssError(1,"MYSQL","SetAttr 'name': name too large for internal representation"); + // return -1; + // } + // obj_internal_CopyPath(&(inf->Pathname), inf->Obj->Pathname); + // strcpy(strrchr(inf->Pathname.Pathbuf,'/')+1,val->String); + // if (rename(inf->Obj->Pathname->Pathbuf, inf->Pathname.Pathbuf) < 0) + // { + // mssError(1,"MYSQL","SetAttr 'name': could not rename structure file node object"); + // return -1; + // } + // obj_internal_CopyPath(inf->Obj->Pathname, &inf->Pathname); + // } + // return 0; + // } + // + // /** Set content type if that was requested. **/ + // if (!strcmp(attrname,"content_type") || !strcmp(attrname,"inner_type")) + // { + // if (datatype != DATA_T_STRING) + // { + // mssError(1,"MYSD","Type mismatch accessing attribute '%s' (should be string)", attrname); + // return -1; + // } + // switch(inf->Type) + // { + // case MYSD_T_DATABASE: val->String = "system/void"; break; + // case MYSD_T_TABLE: val->String = "system/void"; break; + // case MYSD_T_ROWSOBJ: val->String = "system/void"; break; + // case MYSD_T_COLSOBJ: val->String = "system/void"; break; + // case MYSD_T_ROW: val->String = "application/octet-stream"; break; + // case MYSD_T_COLUMN: val->String = "system/void"; break; + // } + // return 0; + // } + // if (!strcmp(attrname,"outer_type")) + // { + // return -1; + // } + // + // if(inf->Type == MYSD_T_ROW) + // { + // for(i=0;iTData->nCols;i++) + // { + // if (!strcmp(inf->TData->Cols[i],attrname)) + // { + // if (*oxt) /** Check if this is part of a larger transaction **/ + // { + // if (type < 0) return -1; + // if (datatype != type) + // { + // mssError(1,"MYSD","Type mismatch setting attribute '%s' [requested=%s, actual=%s]", + // attrname, obj_type_names[datatype], obj_type_names[type]); + // return -1; + // } + // if (strlen(attrname) >= 64) + // { + // mssError(1,"MYSD","Attribute name '%s' too long",attrname); + // return -1; + // } + // (*oxt)->AllocObj = 0; + // (*oxt)->Object = NULL; + // (*oxt)->Status = OXT_S_VISITED; + // strcpy((*oxt)->AttrName, attrname); + // obj_internal_SetTreeAttr(*oxt, type, val); + // } + // else + // { + // if (!val) + // { + // if(mysd_internal_UpdateRow(inf,NULL,i) < 0) return -1; + // } + // else if(datatype == DATA_T_DOUBLE || datatype == DATA_T_INTEGER) + // { + // if(mysd_internal_UpdateRow(inf,mysd_internal_CxDataToMySQL(datatype,(ObjData*)val),i) < 0) return -1; + // } + // else + // { + // if(mysd_internal_UpdateRow(inf,mysd_internal_CxDataToMySQL(datatype,*(ObjData**)val),i) < 0) return -1; + // } + // } + // } + // } + // } + // return 0; + // } + // + // + // /*** mysdAddAttr() - add an attribute to an object. This doesn't always work + // *** for all object types, and certainly makes no sense for some (like unix + // *** files). + // ***/ + // int + // mysdAddAttr(void* inf_v, char* attrname, int type, pObjData val, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // pStructInf new_inf; + // char* ptr; + // + // return -1; + // } + // + // + // /*** mysdOpenAttr() - open an attribute as if it were an object with content. + // *** Not all objects support this type of operation. + // ***/ + // void* + // mysdOpenAttr(void* inf_v, char* attrname, int mode, pObjTrxTree* oxt) + // { + // return NULL; + // } + // + // + // /*** mysdGetFirstMethod() -- return name of First method available on the object. + // ***/ + // char* + // mysdGetFirstMethod(void* inf_v, pObjTrxTree oxt) + // { + // return NULL; + // } + // + // + // /*** mysdGetNextMethod() -- return successive names of methods after the First one. + // ***/ + // char* + // mysdGetNextMethod(void* inf_v, pObjTrxTree oxt) + // { + // return NULL; + // } + // + // + // /*** mysdExecuteMethod() - Execute a method, by name. + // ***/ + // int + // mysdExecuteMethod(void* inf_v, char* methodname, pObjData param, pObjTrxTree oxt) + // { + // return -1; + // } + // + // + // /*** mysqlPresentationHints() - Return a structure containing "presentation hints" + // *** data, which is basically metadata about a particular attribute, which + // *** can include information which relates to the visual representation of + // *** the data on the client. + // ***/ + // pObjPresentationHints + // mysdPresentationHints(void* inf_v, char* attrname, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // pObjPresentationHints hints=NULL; + // pExpression exp; + // int i; + // int datatype; + // char * ptr; + // pParamObjects tmplist; + // + // if (!strcmp(attrname, "name") || !strcmp(attrname, "inner_type") || !strcmp(attrname, "outer_type") || + // !strcmp(attrname, "content_type") || !strcmp(attrname, "annotation") || !strcmp(attrname, "last_modification")) + // { + // if ( (hints = (pObjPresentationHints)nmMalloc(sizeof(ObjPresentationHints))) == NULL) return NULL; + // memset(hints, 0, sizeof(ObjPresentationHints)); + // hints->GroupID=-1; + // hints->VisualLength2=1; + // xaInit(&(hints->EnumList), 8); + // if (!strcmp(attrname, "annotation")) hints->VisualLength = 60; + // else hints->VisualLength = 30; + // if (!strcmp(attrname, "name")) hints->Length = 30; + // else if (!strcmp(attrname, "annotation")) hints->Length = 255; + // else + // { + // hints->Style |= OBJ_PH_STYLE_READONLY; + // hints->StyleMask |= OBJ_PH_STYLE_READONLY; + // } + // return hints; + // } + // + // switch(inf->Type) + // { + // case MYSD_T_DATABASE: break; + // case MYSD_T_TABLE: break; + // case MYSD_T_ROWSOBJ: break; + // case MYSD_T_COLSOBJ: break; + // case MYSD_T_COLUMN: + // if (strcmp(attrname, "datatype")) + // { + // mssError(1, "MYSD", "No attribute %s", attrname); + // return NULL; + // } + // + // if ( (hints = (pObjPresentationHints)nmMalloc(sizeof(ObjPresentationHints))) == NULL) return NULL; + // memset(hints, 0, sizeof(ObjPresentationHints)); + // hints->GroupID=-1; + // hints->VisualLength2=1; + // hints->Style |= OBJ_PH_STYLE_READONLY; + // hints->StyleMask |= OBJ_PH_STYLE_READONLY; + // hints->VisualLength = 15; + // xaInit(&(hints->EnumList), 8); + // return hints; + // break; + // case MYSD_T_ROW: + // /** the attributes of a row are the column names, with the values being the field values **/ + // /** find the name of the column, and get its data type **/ + // for (i=0;iTData->nCols;i++) + // { + // if (!strcmp(attrname, inf->TData->Cols[i])) + // { + // /** Check to see if we already know the hints **/ + // if(inf->TData->ColHints[i]) return objDuplicateHints(inf->TData->ColHints[i]); + // + // /** Otherwise compile them and add them to the table data **/ + // if ( (hints = (pObjPresentationHints)nmMalloc(sizeof(ObjPresentationHints))) == NULL) return NULL; + // memset(hints, 0, sizeof(ObjPresentationHints)); + // datatype = inf->TData->ColCxTypes[i]; + // hints->GroupID=-1; + // hints->VisualLength2=1; + // xaInit(&(hints->EnumList), 8); + // + // /** Note whether it is a primary key field **/ + // if (inf->TData->ColFlags[i] & MYSD_COL_F_PRIKEY) + // hints->Style |= OBJ_PH_STYLE_KEY; + // hints->StyleMask |= OBJ_PH_STYLE_KEY; + // + // /** Set some hints info based on data type information **/ + // if (datatype == DATA_T_STRING) + // { + // /** use the length that we pulled when we grabbed the table data **/ + // if (hints->Length == 0) hints->Length = inf->TData->ColLengths[i]; + // if (hints->VisualLength == 0) hints->VisualLength = inf->TData->ColLengths[i]; + // } + // if (datatype == DATA_T_MONEY) + // { + // hints->Format=nmSysStrdup("money"); + // } + // if (datatype == DATA_T_DATETIME) + // { + // hints->Format=nmSysStrdup("datetime"); + // } + // if (datatype == DATA_T_INTEGER) + // { + // /** use the sizes from the MySQL datatypes **/ + // tmplist = expCreateParamList(); + // expAddParamToList(tmplist,"this",NULL,EXPR_O_CURRENT); + // hints->DefaultExpr = expCompileExpression("0", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // if(!strcmp(inf->TData->ColTypes[i], "tinyint")) + // { + // if(inf->TData->ColFlags[i] & MYSD_COL_F_UNSIGNED) + // { + // hints->MinValue = expCompileExpression("0", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("255", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // else + // { + // hints->MinValue = expCompileExpression("-128", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("127", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // } + // if(!strcmp(inf->TData->ColTypes[i], "smallint")) + // { + // if(inf->TData->ColFlags[i] & MYSD_COL_F_UNSIGNED) + // { + // hints->MinValue = expCompileExpression("0", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("65535", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // else + // { + // hints->MinValue = expCompileExpression("-32768", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("-32767", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // } + // if(!strcmp(inf->TData->ColTypes[i], "mediumint")) + // { + // if(inf->TData->ColFlags[i] & MYSD_COL_F_UNSIGNED) + // { + // hints->MinValue = expCompileExpression("0", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("16777215", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // else + // { + // hints->MinValue = expCompileExpression("-8388608", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("8388607", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // } + // if(!strcmp(inf->TData->ColTypes[i], "int")) + // { + // if(inf->TData->ColFlags[i] & MYSD_COL_F_UNSIGNED) + // { + // hints->MinValue = expCompileExpression("0", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("4294967295", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // else + // { + // hints->MinValue = expCompileExpression("-2147483648", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // hints->MaxValue = expCompileExpression("2147483647", tmplist, MLX_F_ICASE | MLX_F_FILENAMES, 0); + // } + // } + // expFreeParamList(tmplist); + // } + // inf->TData->ColHints[i] = objDuplicateHints(hints); + // break; + // } + // } + // if (i == inf->TData->nCols) + // { + // mssError(1, "MYSD", "No attribute '%s'", attrname); + // return NULL; + // } + // break; + // default: + // mssError(1, "MYSD", "Can't get hints for that type yet"); + // break; + // } + // + // return hints; + // } + // + // + // /*** mysqlInfo() - return object metadata - about the object, not about a + // *** particular attribute. + // ***/ + // int + // mysdInfo(void* inf_v, pObjectInfo info_struct) + // { + // memset(info_struct, sizeof(ObjectInfo), 0); + // return 0; + // } + // + // + // /*** mysqlCommit() - commit any changes made to the underlying data source. + // ***/ + // int + // mysdCommit(void* inf_v, pObjTrxTree* oxt) + // { + // pMysdData inf = MYSD(inf_v); + // struct stat fileinfo; + // int i; + // char sbuf[160]; + // + // /** Was this a create? **/ + // if ((*oxt) && (*oxt)->OpType == OXT_OP_CREATE && (*oxt)->Status != OXT_S_COMPLETE) + // { + // switch (inf->Type) + // { + // case MYSD_T_TABLE: + // /** We'll get to this a little later **/ + // break; + // + // case MYSD_T_ROW: + // /** Perform the insert. **/ + // if (mysd_internal_InsertRow(inf, *oxt) < 0) + // { + // /** FAIL the oxt. **/ + // (*oxt)->Status = OXT_S_FAILED; + // + // return -1; + // } + // + // /** Complete the oxt. **/ + // (*oxt)->Status = OXT_S_COMPLETE; + // break; + // + // case MYSD_T_COLUMN: + // break; + // } + // } + // + // return 0; + // } + // + // + // /*** mysqlInitialize() - initialize this driver, which also causes it to + // *** register itself with the objectsystem. + // ***/ + // int + // mysdInitialize() + // { + // pObjDriver drv; + // + // /** Allocate the driver **/ + // drv = (pObjDriver)nmMalloc(sizeof(ObjDriver)); + // if (!drv) return -1; + // memset(drv, 0, sizeof(ObjDriver)); + // + // /** Initialize globals **/ + // memset(&MYSD_INF,0,sizeof(MYSD_INF)); + // xhInit(&MYSD_INF.DBNodesByPath,255,0); + // xaInit(&MYSD_INF.DBNodeList,127); + // + // /** Init mysql client library **/ + // if (mysql_library_init(0, NULL, NULL) != 0) + // { + // mssError(1, "MYSQL", "Could not init mysql client library"); + // return -1; + // } + // + // /** Setup the structure **/ + // strcpy(drv->Name,"MySQL ObjectSystem Driver"); + // drv->Capabilities = OBJDRV_C_TRANS | OBJDRV_C_FULLQUERY; + // xaInit(&(drv->RootContentTypes),16); + // xaAddItem(&(drv->RootContentTypes),"application/mysql"); + // + // /** Setup the function references. **/ + // drv->Open = mysdOpen; + // drv->Close = mysdClose; + // drv->Create = mysdCreate; + // drv->Delete = mysdDelete; + // drv->DeleteObj = mysdDeleteObj; + // drv->OpenQuery = mysdOpenQuery; + // drv->QueryDelete = mysdQueryDelete; + // drv->QueryFetch = mysdQueryFetch; + // drv->QueryClose = mysdQueryClose; + // drv->Read = mysdRead; + // drv->Write = mysdWrite; + // drv->GetAttrType = mysdGetAttrType; + // drv->GetAttrValue = mysdGetAttrValue; + // drv->GetFirstAttr = mysdGetFirstAttr; + // drv->GetNextAttr = mysdGetNextAttr; + // drv->SetAttrValue = mysdSetAttrValue; + // drv->AddAttr = mysdAddAttr; + // drv->OpenAttr = mysdOpenAttr; + // drv->GetFirstMethod = mysdGetFirstMethod; + // drv->GetNextMethod = mysdGetNextMethod; + // drv->ExecuteMethod = mysdExecuteMethod; + // drv->PresentationHints = mysdPresentationHints; + // drv->Info = mysdInfo; + // drv->Commit = mysdCommit; + // + // nmRegister(sizeof(MysdData),"MysdData"); + // nmRegister(sizeof(MysdQuery),"MysdQuery"); + // + // /** Register the driver **/ + // if (objRegisterDriver(drv) < 0) + // { + // return -1; + // } + // return 0; + // } + // + // MODULE_INIT(mysdInitialize); + // MODULE_PREFIX("mysd"); + // MODULE_DESC("MySQL ObjectSystem Driver"); + // MODULE_VERSION(0,1,0); + // MODULE_IFACE(CX_CURRENT_IFACE); diff --git a/centrallix/osdrivers/fake2.c b/centrallix/osdrivers/fake2.c new file mode 100644 index 000000000..6e91128a3 --- /dev/null +++ b/centrallix/osdrivers/fake2.c @@ -0,0 +1,646 @@ +#include +#include +#include +#include +#include +#include "obj.h" +#include "cxlib/mtask.h" +#include "cxlib/xarray.h" +#include "cxlib/xhash.h" +#include "stparse.h" +#include "st_node.h" +#include "hints.h" +#include "cxlib/mtsession.h" +#include "centrallix.h" +#include "cxlib/strtcpy.h" +#include "cxlib/qprintf.h" +#include "cxlib/util.h" +#include +#include + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2008 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: objdrv_mysql.c */ +/* Author: Greg Beeley (GB) */ +/* Creation: February 21, 2008 */ +/* Description: A MySQL driver for Centrallix. Eventually this driver */ +/* should be merged with the Sybase driver in something of */ +/* an intelligent manner. */ +/************************************************************************/ + + +#define MYSD_MAX_COLS 256 +#define MYSD_MAX_KEYS 8 +#define MYSD_NAME_LEN 32 +#define MYSD_MAX_CONN 16 + +#define MYSD_NODE_F_USECXAUTH 1 /* use Centrallix usernames/passwords */ +#define MYSD_NODE_F_SETCXAUTH 2 /* try to change empty passwords to Centrallix login passwords */ + +/*** Node ***/ +typedef struct + { + char Path[OBJSYS_MAX_PATH]; + char Server[64]; + char Username[64]; + char Password[64]; + char DefaultPassword[64]; + char Database[MYSD_NAME_LEN]; + char AnnotTable[MYSD_NAME_LEN]; + char Description[256]; + int MaxConn; + int Flags; + pSnNode SnNode; + XArray Conns; + int ConnAccessCnt; + XHashTable Tables; + XArray Tablenames; + int LastAccess; + } + MysdNode, *pMysdNode; + + +/*** Connection data ***/ +typedef struct + { + MYSQL Handle; + char Username[64]; + char Password[64]; + pMysdNode Node; + int Busy; + int LastAccess; + } + MysdConn, *pMysdConn; + + +/*** Table data ***/ +typedef struct + { + char Name[MYSD_NAME_LEN]; + unsigned char ColFlags[MYSD_MAX_COLS]; + unsigned char ColCxTypes[MYSD_MAX_COLS]; + unsigned char ColKeys[MYSD_MAX_COLS]; + char* Cols[MYSD_MAX_COLS]; + char* ColTypes[MYSD_MAX_COLS]; + unsigned int ColLengths[MYSD_MAX_COLS]; + pObjPresentationHints ColHints[MYSD_MAX_COLS]; + int nCols; + char* Keys[MYSD_MAX_KEYS]; + int KeyCols[MYSD_MAX_KEYS]; + int nKeys; + pMysdNode Node; + char* Annotation; + pParamObjects ObjList; + pExpression RowAnnotExpr; + } + MysdTable, *pMysdTable; + +#define MYSD_COL_F_NULL 1 /* column allows nulls */ +#define MYSD_COL_F_PRIKEY 2 /* column is part of primary key */ +#define MYSD_COL_F_UNSIGNED 4 /* Flag for unsigned on integer fields */ + + +/*** Structure used by this driver internally. ***/ +typedef struct + { + Pathname Pathname; + char* Name; + int Type; + int Flags; + pObject Obj; + int Mask; + int CurAttr; + pMysdNode Node; + char* RowBuf; + MYSQL_ROW Row; + MYSQL_RES * Result; + char* ColPtrs[MYSD_MAX_COLS]; + unsigned short ColLengths[MYSD_MAX_COLS]; + pMysdTable TData; + union + { + DateTime Date; + MoneyType Money; + IntVec IV; + StringVec SV; + } Types; + char Objname[256]; + } + MysdData, *pMysdData; + +#define MYSD_T_DATABASE 1 +#define MYSD_T_TABLE 2 +#define MYSD_T_COLSOBJ 3 +#define MYSD_T_ROWSOBJ 4 +#define MYSD_T_COLUMN 5 +#define MYSD_T_ROW 6 + + +#define MYSD(x) ((pMysdData)(x)) + +/*** Structure used by queries for this driver. ***/ +typedef struct + { + pMysdData Data; + char NameBuf[256]; + XString Clause; + int ItemCnt; + } + MysdQuery, *pMysdQuery; + + +/*** GLOBALS ***/ +struct + { + XHashTable DBNodesByPath; + XArray DBNodeList; + int AccessCnt; + int LastAccess; + } + MYSD_INF; + +MYSQL_RES* mysd_internal_RunQuery(pMysdNode node, char* stmt, ...); +MYSQL_RES* mysd_internal_RunQuery_conn(pMysdConn conn, pMysdNode node, char* stmt, ...); +MYSQL_RES* mysd_internal_RunQuery_conn_va(pMysdConn conn, pMysdNode node, char* stmt, va_list ap); + +/** This value is returned if the query failed. If NULL is returned from + * ** the RunQuery functions, it means "no result set" but success. It is + * ** equal to 0xFFFFFFFF on 32-bit platforms, and 0xFFFFFFFFFFFFFFFFLL on + * ** 64-bit platforms. + * **/ +#define MYSD_RUNQUERY_ERROR ((MYSQL_RES*)~((long)0)) + +/*** mysd_internal_GetConn() - given a specific database node, get a connection + * *** to the server with a given login (from mss thread structures). + * ***/ +pMysdConn +mysd_internal_GetConn(pMysdNode node) + { + MYSQL_RES * result; + pMysdConn conn; + int i, conn_cnt, found; + int min_access; + char* username; + char* password; + + /** Is one available from the node's connection pool? **/ + conn_cnt = xaCount(&node->Conns); + + /** Use system auth? **/ + if (node->Flags & MYSD_NODE_F_USECXAUTH) + { + /** Do we have permission to do this? **/ + if (!(CxGlobals.Flags & CX_F_ENABLEREMOTEPW)) + { + mssError(1,"MYSD","use_system_auth requested, but Centrallix global enable_send_credentials is turned off"); + return NULL; + } + + /** Get usernamename/password from session **/ + username = mssUserName(); + password = mssPassword(); + + if(!username || !password) + { + mssError(1,"MYSD","Connect to database: username and/or password not supplied"); + return NULL; + } + } + else + { + /** Use usernamename/password from node **/ + username = node->Username; + password = node->Password; + } + + conn = NULL; + for(i=0;iConns, i); + if (!conn->Busy && !strcmp(username, conn->Username) && !strcmp(password, conn->Password)) + { + if (mysql_ping(&conn->Handle) != 0) + { + /** Got disconnected. Discard the connection. **/ + mysql_close(&conn->Handle); + memset(conn->Password, 0, sizeof(conn->Password)); + xaRemoveItem(&node->Conns, i); + nmFree(conn, sizeof(MysdConn)); + i--; + conn_cnt--; + conn = NULL; + continue; + } + break; + } + conn = NULL; + } + + /** Didn't get one? **/ + if (!conn) + { + if (conn_cnt < node->MaxConn) + { + /** Below pool maximum? Alloc if so **/ + conn = (pMysdConn)nmMalloc(sizeof(MysdConn)); + if (!conn) + { + mssError(0,"MYSD","Could not connect to database server"); + return NULL; + } + conn->Node = node; + } + else + { + /** Try to free and reuse a connection **/ + min_access = 0x7fffffff; + found = -1; + for(i=0;iConns, i); + if (!conn->Busy && conn->LastAccess < min_access) + { + min_access = conn->LastAccess; + found = i; + } + } + if (found < 0) + { + mssError(1, "MYSD", "Connection limit (%d) reached for server [%s]", + node->MaxConn, node->Server); + return NULL; + } + conn = (pMysdConn)xaGetItem(&node->Conns, found); + mysql_close(&conn->Handle); + memset(conn->Password, 0, sizeof(conn->Password)); + xaRemoveItem(&node->Conns, found); + nmFree(conn, sizeof(MysdConn)); + } + + /** Attempt connection **/ + if (mysql_init(&conn->Handle) == NULL) + { + mssError(1, "MYSD", "Memory exhausted"); + nmFree(conn, sizeof(MysdConn)); + return NULL; + } + if (mysql_real_connect(&conn->Handle, node->Server, username, password, node->Database, 0, NULL, 0) == NULL) + { + if (node->Flags & MYSD_NODE_F_SETCXAUTH) + { + if (mysql_real_connect(&conn->Handle, node->Server, username, node->DefaultPassword, node->Database, 0, NULL, 0) == NULL) + { + mssError(1, "MYSD", "Could not connect to MySQL server [%s], DB [%s]: %s", + node->Server, node->Database, mysql_error(&conn->Handle)); + mysql_close(&conn->Handle); + nmFree(conn, sizeof(MysdConn)); + return NULL; + } + + /** Successfully connected using user default password. + * ** Now try to change the password. + * **/ + result = mysd_internal_RunQuery_conn(conn, node, "SET PASSWORD = PASSWORD('?')", password); + + if (result == MYSD_RUNQUERY_ERROR) + mssError(1, "MYSD", "Warning: could not update password for user [%s]: %s", + username, mysql_error(&conn->Handle)); + } + else + { + mssError(1, "MYSD", "Could not connect to MySQL server [%s], DB [%s]: %s", + node->Server, node->Database, mysql_error(&conn->Handle)); + mysql_close(&conn->Handle); + nmFree(conn, sizeof(MysdConn)); + return NULL; + } + } + + /** Success! **/ + strtcpy(conn->Username, username, sizeof(conn->Username)); + strtcpy(conn->Password, password, sizeof(conn->Password)); + xaAddItem(&node->Conns, conn); + } + + /** Make it busy **/ + conn->Busy = 1; + conn->LastAccess = (node->ConnAccessCnt++); + + return conn; + } + + +/*** mysd_internal_ReleaseConn() - release a connection back to the connection + * *** pool. Also sets the pointer to NULL. + * ***/ +void +mysd_internal_ReleaseConn(pMysdConn * conn) + { + + /** Release it **/ + assert((*conn)->Busy); + (*conn)->Busy = 0; + (*conn) = NULL; + + return; + } + +/*** mysd_internal_RunQuery() - safely runs a query on the database + * *** This works simarly to prepared statments using the question mark syntax. + * *** Instead of calling bindParam for each argument as is done in general, + * *** all of the arguments to be replaced are passed as varargs + * *** + * *** There are some differences: + * *** ?d => decimal. inserts using sprintf("%d",int) + * *** ?v => quoted or nonquoted, params are (char* str, int add_quote), see ?a. + * *** ?q => used for query clauses. + * *** same as ? except without escaping + * *** only use if you know the input is clean and is already a query segment + * *** ?a => array, params for this are (char** array, char add_quote[], int length, char separator + * *** it will become: item1,item2,items3 (length = 3, separator = ',') + * *** '?a' => same as array except with individual quoting specified + * *** it will become: 'item1','item2','items3' (length = 3, separator = ',') + * *** ?n => transform name of object into criteria (field1 = 'value1' and field2 = 'value2') + * *** add_quote can be left NULL, in which case nothing gets quoted with ?a. + * *** (add_quote has no effect on '?a' forms). Otherwise, a non-'\0' value + * *** for add_quote[x] means to add single quotes '' onto the value. + * *** + * *** All parameters are sanatized with mysql_real_escape_string before + * *** the query is built + * *** This WILL NOT WORK WITH BINARY DATA + * ***/ +MYSQL_RES* +mysd_internal_RunQuery_conn_va(pMysdConn conn, pMysdNode node, char* stmt, va_list ap) + { + MYSQL_RES * result = MYSD_RUNQUERY_ERROR; + XString query; + int i, j; + int length = 0; + char * start; + char ** array = NULL; + int items = 0; + char separator; + char quote = 0x00; + char tmp[32]; + char * add_quote; + char * str; + char * endstr; + int err; + char * errtxt; + char ch; + pMysdData data; + + xsInit(&query); + + length=-1; + start=stmt; + for(i = 0; stmt[i]; i++) + { + length++; + if(stmt[i] == '?') + { + /** throw on everything new that is just constant **/ + if(xsConcatenate(&query,start,length)) goto error; + /** do the insertion **/ + if(stmt[i+1]=='a') /** handle arrays **/ + { + array = va_arg(ap,char**); + add_quote = va_arg(ap,char*); + items = va_arg(ap,int); + separator = va_arg(ap,int); + if(stmt[i+2] == '\'' || stmt[i+2]=='`') quote = stmt[i+2]; else quote = 0x00; + for(j = 0; j < items; j++) + { + if(j > 0) + { + if(quote) if(xsConcatenate(&query,"e,1)) goto error; + if(xsConcatenate(&query,&separator,1)) goto error; + if(quote) if(xsConcatenate(&query,"e,1)) goto error; + } + if (!array[j]) + { + xsConcatenate(&query, "null", 4); + } + else + { + if (!quote && add_quote && add_quote[j]) + xsConcatenate(&query, "'", 1); + if(mysd_internal_SafeAppend(&conn->Handle,&query,array[j])) goto error; + if (!quote && add_quote && add_quote[j]) + xsConcatenate(&query, "'", 1); + } + } + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='v') /** quoted / nonquoted **/ + { + str = va_arg(ap,char*); + quote = va_arg(ap,int); + if (!str) + { + xsConcatenate(&query, "null", 4); + } + else + { + if (quote) + xsConcatenate(&query, "'", 1); + if(mysd_internal_SafeAppend(&conn->Handle,&query,str)) goto error; + if (quote) + xsConcatenate(&query, "'", 1); + } + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='d') /** handle integers **/ + { + sprintf(tmp,"%d",va_arg(ap,int)); + if(mysd_internal_SafeAppend(&conn->Handle,&query,tmp)) goto error; + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='q') /** handle pre-sanitized query sections **/ + { + xsConcatenate(&query,va_arg(ap,char*),-1); + start = &stmt[i+2]; + i++; + } + else if(stmt[i+1]=='n') /** object name criteria - expect pMysdData **/ + { + data = va_arg(ap, pMysdData); + xsConcatenate(&query, " (", 2); + str = data->Name; + for(j=0; jTData->nKeys; j++) + { + endstr = strchr(str, '|'); + if (!endstr) + endstr = str + strlen(str); + if (j != 0) + xsConcatenate(&query, " and ", 5); + xsConcatenate(&query, "`", 1); + if (mysd_internal_SafeAppend(&conn->Handle, &query, data->TData->Keys[j])) goto error; + xsConcatenate(&query, "` = '", 5); + ch = *endstr; + *endstr = '\0'; + if (mysd_internal_SafeAppend(&conn->Handle, &query, str)) + { + *endstr = ch; + goto error; + } + *endstr = ch; + xsConcatenate(&query, "'", 1); + str = (*endstr)?(endstr+1):(endstr); + } + xsConcatenate(&query, ") ", 2); + start = &stmt[i+2]; + i++; + } + else /** handle plain sanitize+insert **/ + { + if(mysd_internal_SafeAppend(&conn->Handle,&query,va_arg(ap,char*))) goto error; + start = &stmt[i+1]; + } + length = -1; + } + } + /** insert the last constant bit **/ + if(xsConcatenate(&query,start,-1)) goto error; + + /** If you want to do something with all the DB queries + * ** this is the place + * **/ + /* printf("TEST: query=\"%s\"\n",query.String); */ + + if(mysql_query(&conn->Handle,query.String)) goto error; + result = mysql_store_result(&conn->Handle); + err = mysql_errno(&conn->Handle); + if (err) + { + errtxt = (char*)mysql_error(&conn->Handle); + mssError(1,"MYSD","SQL command failed: %s", errtxt); + if (result) mysql_free_result(result); + result = MYSD_RUNQUERY_ERROR; + if (err == 1022 || err == 1061 || err == 1062) + errno = EEXIST; + else + errno = EINVAL; + } + + error: + xsDeInit(&query); + return result; + } + +MYSQL_RES* +mysd_internal_RunQuery_conn(pMysdConn conn, pMysdNode node, char* stmt, ...) + { + MYSQL_RES * result = NULL; + va_list ap; + + va_start(ap,stmt); + result = mysd_internal_RunQuery_conn_va(conn, node, stmt, ap); + va_end(ap); + + return result; + } + +MYSQL_RES* +mysd_internal_RunQuery(pMysdNode node, char* stmt, ...) + { + MYSQL_RES * result = NULL; + pMysdConn conn = NULL; + va_list ap; + + /**start up ap and create query XString **/ + + va_start(ap,stmt); + + if(!(conn = mysd_internal_GetConn(node))) + return NULL; + + result = mysd_internal_RunQuery_conn_va(conn, node, stmt, ap); + + mysd_internal_ReleaseConn(&conn); + + va_end(ap); + + return result; + } + + +/*** mysd_internal_SafeAppend - appends a string on a query + * *** this uses mysql_real_escape_string and requires a connection + * ***/ + +int +mysd_internal_SafeAppend(MYSQL* conn, pXString dst, char* src) + { + char* escaped_src; + int length; + int rval = 0; + length = strlen(src); + + escaped_src = nmMalloc(length*2+1); + mysql_real_escape_string(conn,escaped_src,src,length); + if(xsConcatenate(dst,escaped_src,-1)) rval = -1; + + nmFree(escaped_src,length*2+1); + + return rval; + } + +/*** mysd_internal_CxDataToMySQL() - convert cx data to mysql field values + * ***/ +char* +mysd_internal_CxDataToMySQL(int type, pObjData val) + { + char* tmp; + int length; + int j; + + /** Handle nulls **/ + if (!val) + return NULL; + + /** Convert based on data type **/ + if (type == DATA_T_INTEGER || type == DATA_T_DOUBLE) + { + return objDataToStringTmp(type,val,0); + } + if (type == DATA_T_DATETIME) + { + return (char*)objFormatDateTmp((pDateTime)val,"yyyy-MM-dd HH:mm:ss"); + } + if (type == DATA_T_MONEY) + { + return (char*)objFormatMoneyTmp((pMoneyType)val,"^.####"); + } + if (type == DATA_T_STRING) + { + return objDataToStringTmp(type,val,0); + } + return NULL; + } + diff --git a/centrallix/tests/test_expfn_char_length_00.cmp b/centrallix/tests/test_expfn_char_length_00.cmp index 1288ec26c..2d64134ce 100644 --- a/centrallix/tests/test_expfn_char_length_00.cmp +++ b/centrallix/tests/test_expfn_char_length_00.cmp @@ -3,4 +3,3 @@ Attribute [char_length("a")]: integer 1 Attribute [char_length("")]: integer 0 Attribute [char_length(null)]: integer NULL Attribute [char_length("abcde"*999999)]: integer 4999995 -Attribute [char_length("كتاب")]: integer 8 diff --git a/centrallix/tests/test_expfn_char_length_00.to b/centrallix/tests/test_expfn_char_length_00.to index 6b4f318c5..28d47848b 100644 --- a/centrallix/tests/test_expfn_char_length_00.to +++ b/centrallix/tests/test_expfn_char_length_00.to @@ -5,4 +5,3 @@ query select 'char_length("a")' = char_length("a") query select 'char_length("")' = char_length("") query select 'char_length(null)' = char_length(null) query select 'char_length("abcde"*999999)' = char_length("abcde" * 999999) -query select 'char_length("كتاب")' = char_length("كتاب") diff --git a/centrallix/tests/test_expfn_utf8charindex_00.to b/centrallix/tests/test_expfn_utf8charindex_00.to index 1dfdde062..cffa6e707 100644 --- a/centrallix/tests/test_expfn_utf8charindex_00.to +++ b/centrallix/tests/test_expfn_utf8charindex_00.to @@ -1,22 +1,46 @@ ##NAME charindex() function -query select 'charindex("abc", "abcdefg")' = charindex("abc", "abcdefg") -query select 'charindex("cde", "abcdefg")' = charindex("cde", "abcdefg") -query select 'charindex("efg", "abcdefg")' = charindex("efg", "abcdefg") -query select 'charindex("fgh", "abcdefg")' = charindex("fgh", "abcdefg") -query select 'charindex("1ab", "abcdefg")' = charindex("1ab", "abcdefg") -query select 'charindex("a", "abcdefg")' = charindex("a", "abcdefg") -query select 'charindex("d", "abcdefg")' = charindex("d", "abcdefg") -query select 'charindex("g", "abcdefg")' = charindex("g", "abcdefg") -query select 'charindex("h", "abcdefg")' = charindex("h", "abcdefg") -query select 'charindex("1", "abcdefg")' = charindex("1", "abcdefg") -query select 'charindex("abc", "a")' = charindex("abc", "a") -query select 'charindex("abc", "abc")' = charindex("abc", "abc") -query select 'charindex("", "abcdefg")' = charindex("", "abcdefg") -query select 'charindex("a", "")' = charindex("a", "") -query select 'charindex("", "")' = charindex("", "") -query select 'charindex(null, "abcdefg")' = charindex(null, "abcdefg") -query select 'charindex("a", null)' = charindex("a", null) -query select 'charindex(null, null)' = charindex(null, null) -query select 'charindex("", null)' = charindex("", null) -query select 'charindex(null, "")' = charindex(null, "") +query select 'utf8_charindex("abc", "abcdefg")' = utf8_charindex("abc", "abcdefg") +query select 'utf8_charindex("abc", "abcdefghijklmnopqrstuvwxyz")' = utf8_charindex("abc", "abcdefghijklmnopqrstuvwxyz") +query select 'utf8_charindex("cde", "abcdefg")' = utf8_charindex("cde", "abcdefg") +query select 'utf8_charindex("efg", "abcdefg")' = utf8_charindex("efg", "abcdefg") +query select 'utf8_charindex("fgh", "abcdefg")' = utf8_charindex("fgh", "abcdefg") +query select 'utf8_charindex("1ab", "abcdefg")' = utf8_charindex("1ab", "abcdefg") +query select 'utf8_charindex("a", "abcdefg")' = utf8_charindex("a", "abcdefg") +query select 'utf8_charindex("d", "abcdefg")' = utf8_charindex("d", "abcdefg") +query select 'utf8_charindex("g", "abcdefg")' = utf8_charindex("g", "abcdefg") +query select 'utf8_charindex("h", "abcdefg")' = utf8_charindex("h", "abcdefg") +query select 'utf8_charindex("1", "abcdefg")' = utf8_charindex("1", "abcdefg") +query select 'utf8_charindex("abc", "a")' = utf8_charindex("abc", "a") +query select 'utf8_charindex("abc", "abc")' = utf8_charindex("abc", "abc") +query select 'utf8_charindex("", "abcdefg")' = utf8_charindex("", "abcdefg") +query select 'utf8_charindex("a", "")' = utf8_charindex("a", "") +query select 'utf8_charindex("", "")' = utf8_charindex("", "") +query select 'utf8_charindex(null, "abcdefg")' = utf8_charindex(null, "abcdefg") +query select 'utf8_charindex("a", null)' = utf8_charindex("a", null) +query select 'utf8_charindex(null, null)' = utf8_charindex(null, null) +query select 'utf8_charindex("", null)' = utf8_charindex("", null) +query select 'utf8_charindex(null, "")' = utf8_charindex(null, "") +query select 'utf8_charindex(:Full, :Part) from /tests/Foreign2.csv/rows' = utf8_charindex(:Full, :Part) from /tests/Foreign2.csv/rows +#query select 'utf8_charindex("ελπίδα", "δα")' = utf8_charindex("ελπίδα", "δα") +#query select 'utf8_charindex("Adiós", "s")' = charindex("Adiós", "s") +#query select 'utf8_charindex("Glück", "Glück")' = charindex("Glück", "Glück") +#query select 'utf8_charindex("АДЖИ", "N")' = charindex("АДЖИ", "N") +#query select 'utf8_charindex("français", "rançai")' = charindex("français", "rançai") +#query select 'utf8_charindex("Swạsdī", i")' = charindex("Swạsdī","i") +#query select 'utf8_charindex("a", "Swạs")' = charindex("a", "Swạs") +#query select 'utf8_charindex("Салом", "Сал")' = charindex("Салом", "Сал") +#query select 'utf8_charindex("Салом", "")' = charindex("Салом", "") +#query select 'utf8_charindex("", "χ")' = charindex("", "χ") +#query select 'utf8_charindex("ρά", "ά")' = charindex("ρά", "ά") +#query select 'utf8_charindex("ρά", "p")' = charindex("ρά", "ρά") +#query select 'utf8_charindex("ρά", null)' = charindex("ρά", null) +#query select 'utf8_charindex("χ", "χ")' = charindex("χ", "χ") +#query select 'utf8_charindex("баривчилж байна", "лж ба")' = charindex("баривчилж байна", "лж ба") +#query select 'utf8_charindex("!$%!^&^*!^&*", "!^&*")' = charindex("!$%!^&^*!^&*", "!^&*") +#query select 'utf8_charindex(null, "ДЖ")' = charindex(null, "ДЖ") +#query select 'utf8_charindex("123456789", "5")' = charindex("123456789", "5") + + + + diff --git a/centrallix/tests/test_expfn_utf8charlength_00.cmp b/centrallix/tests/test_expfn_utf8charlength_00.cmp new file mode 100755 index 000000000..c6ab5446a --- /dev/null +++ b/centrallix/tests/test_expfn_utf8charlength_00.cmp @@ -0,0 +1,16 @@ +Attribute [utf8_char_length("abc")]: integer 3 +Attribute [utf8_char_length("a")]: integer 1 +Attribute [utf8_char_length("")]: integer 0 +Attribute [utf8_char_length(null)]: integer NULL +Attribute [utf8_char_length("abcde"*999999]: integer 4999995 +Attribute [utf8_char_length("كتاب")]: integer 4 +Attribute [utf8_char_length(:String) from ]: integer 6 +Attribute [utf8_char_length(:String) from ]: integer 5 +Attribute [utf8_char_length(:String) from ]: integer 5 +Attribute [utf8_char_length(:String) from ]: integer 4 +Attribute [utf8_char_length(:String) from ]: integer 8 +Attribute [utf8_char_length(:String) from ]: integer 6 +Attribute [utf8_char_length(:String) from ]: integer 5 +Attribute [utf8_char_length(:String) from ]: integer 2 +Attribute [utf8_char_length(:String) from ]: integer 1 +Attribute [utf8_char_length(:String) from ]: integer 24 diff --git a/centrallix/tests/test_expfn_utf8charlength_00.to b/centrallix/tests/test_expfn_utf8charlength_00.to index 6b4f318c5..52f9881a9 100644 --- a/centrallix/tests/test_expfn_utf8charlength_00.to +++ b/centrallix/tests/test_expfn_utf8charlength_00.to @@ -1,8 +1,9 @@ ##NAME char_length() function -query select 'char_length("abc")' = char_length("abc") -query select 'char_length("a")' = char_length("a") -query select 'char_length("")' = char_length("") -query select 'char_length(null)' = char_length(null) -query select 'char_length("abcde"*999999)' = char_length("abcde" * 999999) -query select 'char_length("كتاب")' = char_length("كتاب") +query select 'utf8_char_length("abc")' = char_length("abc") +query select 'utf8_char_length("a")' = char_length("a") +query select 'utf8_char_length("")' = char_length("") +query select 'utf8_char_length(null)' = char_length(null) +query select 'utf8_char_length("abcde"*999999)' = char_length("abcde" * 999999) +query select 'utf8_char_length("كتاب")' = char_length("كتاب") +query select 'utf8_char_length(:String) from /tests/Foreign.csv/rows' = utf8_char_length(:String) from /tests/Foreign.csv/rows diff --git a/centrallix/tests/test_expfn_utf8replace_00.cmp b/centrallix/tests/test_expfn_utf8replace_00.cmp new file mode 100755 index 000000000..2bb756c4e --- /dev/null +++ b/centrallix/tests/test_expfn_utf8replace_00.cmp @@ -0,0 +1,31 @@ +Attribute [column_000]: string "abxefg" +Attribute [column_000]: string "abxyzefg" +Attribute [column_000]: string "" +Attribute [column_000]: string "" +Attribute [column_000]: string "g" +Attribute [column_000]: string "a" +Attribute [column_000]: string "abcdefg" +Attribute [column_000]: string "abcdefg" +Attribute [column_000]: string "bbbbbbb" +Attribute [column_000]: string "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +Attribute [column_000]: string "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +Attribute [column_000]: string "" +Attribute [column_000]: string "bbb" +Attribute [column_000]: string "xyzbxyzbxyzbxyz" +Attribute [column_000]: string "axyzaxyzaxyza" +Attribute [column_000]: string "xyzxyzxyza" +Attribute [column_000]: string "axyzxyzxyz" +Attribute [column_000]: string "bbb" +Attribute [column_000]: string "xyzbxyzbxyzb" +Attribute [column_000]: string "axyzaxyzaxyz" +Attribute [column_000]: string "xyzxyzxyz" +Attribute [column_000]: string "axyzxyzb" +Attribute [column_000]: string NULL +Attribute [column_000]: string NULL +Attribute [column_000]: string "aЖdefg" +Attribute [column_000]: string "abcdefСалом" +Attribute [column_000]: string "ﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭﺢﺑﺎﻣﺭ" +Attribute [column_000]: string "вчά" +Attribute [column_000]: string "frελπnçελπis" +Attribute [column_000]: string "Gluck" +Attribute [column_000]: string "GlGlückck" diff --git a/centrallix/tests/test_expfn_utf8replace_00.to b/centrallix/tests/test_expfn_utf8replace_00.to index 9b7fcc3c9..e01c9669e 100644 --- a/centrallix/tests/test_expfn_utf8replace_00.to +++ b/centrallix/tests/test_expfn_utf8replace_00.to @@ -1,4 +1,35 @@ ##NAME utf8_replace() function -query select utf8_replace("abcdefg","cd","x") +query select replace("abcdefg","cd","x") +query select replace("abcdefg","cd","xyz") +query select replace("abcdefg","abcdefg","") +query select replace("abcdefg","abcdefg",NULL) +query select replace("abcdefg","abcdef","") +query select replace("abcdefg","bcdefg","") +query select replace("abcdefg","","") +query select replace("abcdefg","","abc") +query select replace("aaaaaaa","a","b") +query select replace("aaaaaaa","a","012345678901234567890123456789") +query select replace("aaaaaaaaaaaaaaaaaaaa","a","012345678901234567890123456789") +query select replace("aaaaaaa","a","") +query select replace("abababa","a","") +query select replace("abababa","a","xyz") +query select replace("abababa","b","xyz") +query select replace("abababa","ab","xyz") +query select replace("abababa","ba","xyz") +query select replace("ababab","a","") +query select replace("ababab","a","xyz") +query select replace("ababab","b","xyz") +query select replace("ababab","ab","xyz") +query select replace("ababab","ba","xyz") +query select replace(null, "", "") +query select replace("", null, "") + +query select replace("abcdefg", "bc", "Ж") +query select replace("abcdefg", "g", "Салом") +query select replace("aaaaaaaaa", "a", "ﺢﺑﺎﻣﺭ") +query select replace("ρά","ρ", "вч") +query select replace("français", "a", "ελπ") +query select replace("Glück","ü", "u") +query select replace("Glück","ü", "Glück") diff --git a/centrallix/tests/test_expfn_utf8sub_00.cmp b/centrallix/tests/test_expfn_utf8sub_00.cmp new file mode 100755 index 000000000..98fcc81c7 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8sub_00.cmp @@ -0,0 +1,76 @@ +Attribute [column_000]: string "Color: Black | Group: Monochrome" +Attribute [column_000]: string "Color: White | Group: Monochrome" +Attribute [column_000]: string "Color: Grey | Group: Monochrome" +Attribute [column_000]: string "Color: Charcoal | Group: Monochrome" +Attribute [column_000]: string "Color: Green | Group: Color" +Attribute [column_000]: string "Color: Yellow | Group: Color" +Attribute [column_000]: string "Color: Red | Group: Color" +Attribute [column_000]: string "Color: Blue | Group: Color" +Attribute [column_000]: string "Color: Purple | Group: Color" +Attribute [column_000]: string "Color: Orange | Group: Color" +Attribute [column_000]: string "Color: Violet | Group: Color" +Attribute [column_000]: string "Color: Black" +Attribute [column_000]: string "Color: White" +Attribute [column_000]: string "Color: Grey" +Attribute [column_000]: string "Color: Charcoal" +Attribute [column_000]: string "Color: Green" +Attribute [column_000]: string "Color: Yellow" +Attribute [column_000]: string "Color: Red" +Attribute [column_000]: string "Color: Blue" +Attribute [column_000]: string "Color: Purple" +Attribute [column_000]: string "Color: Orange" +Attribute [column_000]: string "Color: Violet" +Attribute [column_000]: string "Flat Flat Flat is Non-reflective Non-reflective Non-reflective" +Attribute [column_000]: string "Eggshell Eggshell Eggshell is Slightly reflective Slightly reflective Slightly reflective" +Attribute [column_000]: string "Satin Satin Satin is Somewhat reflective Somewhat reflective Somewhat reflective" +Attribute [column_000]: string "Semi-Gloss Semi-Gloss Semi-Gloss is Reflective Reflective Reflective" +Attribute [column_000]: string "Gloss Gloss Gloss is Very reflective Very reflective Very reflective" +Attribute [column_000]: string "Price Color Sheen" +Attribute [column_000]: string "$5 Green Flat" +Attribute [column_000]: string "$5 Green Eggshell" +Attribute [column_000]: string "$5 Green Satin" +Attribute [column_000]: string "$5 Green Semi-Gloss" +Attribute [column_000]: string "$5 Green Gloss" +Attribute [column_000]: string "$5 Yellow Flat" +Attribute [column_000]: string "$5 Yellow Eggshell" +Attribute [column_000]: string "$5 Yellow Satin" +Attribute [column_000]: string "$5 Yellow Semi-Gloss" +Attribute [column_000]: string "$5 Yellow Gloss" +Attribute [column_000]: string "$5 Red Flat" +Attribute [column_000]: string "$5 Red Eggshell" +Attribute [column_000]: string "$5 Red Satin" +Attribute [column_000]: string "$5 Red Semi-Gloss" +Attribute [column_000]: string "$5 Red Gloss" +Attribute [column_000]: string "$5 Blue Flat" +Attribute [column_000]: string "$5 Blue Eggshell" +Attribute [column_000]: string "$5 Blue Satin" +Attribute [column_000]: string "$5 Blue Semi-Gloss" +Attribute [column_000]: string "$5 Blue Gloss" +Attribute [column_000]: string "$5 Purple Flat" +Attribute [column_000]: string "$5 Purple Eggshell" +Attribute [column_000]: string "$5 Purple Satin" +Attribute [column_000]: string "$5 Purple Semi-Gloss" +Attribute [column_000]: string "$5 Purple Gloss" +Attribute [column_000]: string "$5 Orange Flat" +Attribute [column_000]: string "$5 Orange Eggshell" +Attribute [column_000]: string "$5 Orange Satin" +Attribute [column_000]: string "$5 Orange Semi-Gloss" +Attribute [column_000]: string "$5 Orange Gloss" +Attribute [column_000]: string "$5 Violet Flat" +Attribute [column_000]: string "$5 Violet Eggshell" +Attribute [column_000]: string "$5 Violet Satin" +Attribute [column_000]: string "$5 Violet Semi-Gloss" +Attribute [column_000]: string "$5 Violet Gloss" +Attribute [column_000]: string "" +Attribute [column_000]: string "" +Attribute [column_000]: string "this is a longer test" +Attribute [column_000]: string "short test" +Attribute [substitute(null,null)]: string NULL +Attribute [column_000]: string "English: hello Translation: مرحبا Language: Arabic" +Attribute [column_000]: string "English: cheese Translation: càise Language: Scottish Gaelic" +Attribute [column_000]: string "English: dinosaur Translation: risaeðla Language: Icelandic" +Attribute [column_000]: string "English: goodbye Translation: adiós Language: Spanish" +Attribute [column_000]: string "English: tommy Translation: トミー Language: Japanese" +Attribute [column_000]: string "English: missions Translation: миссиялар Language: Kazakh" +Attribute [column_000]: string "English: Jesus Translation: יאשקע Language: Yiddish" +Attribute [column_000]: string "English: Jesus Translation: พระเยซ Language: Thai" diff --git a/centrallix/tests/test_expfn_utf8sub_00.to b/centrallix/tests/test_expfn_utf8sub_00.to new file mode 100644 index 000000000..04c75d312 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8sub_00.to @@ -0,0 +1,24 @@ +##NAME UTF-8 substitute function() + +# basic example +query select substitute("Color: [:row:Color] | Group: [:row:ColorGroup]", "row=r") from /tests/TestLevel1.csv/rows/ r + +# without mapping string +query select substitute("Color: [:r:Color]") from /tests/TestLevel1.csv/rows/ r + +# using objects multiple times +query select substitute("[:row:Sheen] [:row:Sheen] [:row:Sheen] is [:row:Description] [:row:Description] [:row:Description]", "row=r") from /tests/TestLevel2.csv/rows/ r + +# using objects from multiple sources +query select "Price\tColor\tSheen" +query select substitute("$5\t[:t1:Color]\t[:t2:Sheen]", "t1=a,t2=b") from /tests/TestLevel1.csv/rows/ a, /tests/TestLevel2.csv/rows/ b where :a:ColorGroup="Color" + +# using objects with empty string fields +query select substitute("[:row:f_string]", "row=r") from /tests/Datatypes.csv/rows/ r where :r:f_integer<-700 + +# passing in nulls +query select 'substitute(null,null)' = substitute(null,null) + +# using ojects with foreign languages +query select substitute("English: [:row:English]\tTranslation: [:row:Translation]\tLanguage: [:row:Language]", "row=r") from /tests/Foreign3.csv/rows r + diff --git a/centrallix/tests/test_overlong_00.to b/centrallix/tests/test_overlong_00.to index 895cd9e31..c634b4205 100644 --- a/centrallix/tests/test_overlong_00.to +++ b/centrallix/tests/test_overlong_00.to @@ -2,6 +2,8 @@ query select overlong("abc") query select overlong("\x21") +query select overlong(U-000007FF) +query select overlong("\U000007FF") query select overlong("\\xC0\\xA1") query select overlong("\\xE2\\x82\\xAC") -query select overlong("\\xF0\\x82\\x82\\xAC") +query select overlong("\xF0\x82\x82\xAC") From 456e89f19ab42c91fbba889ca4e4cf7c94892b43 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Wed, 8 Jul 2020 08:36:21 -0600 Subject: [PATCH 033/124] Beginning modifications to database connection --- centrallix/osdrivers/objdrv_mysql.c | 39 ++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/centrallix/osdrivers/objdrv_mysql.c b/centrallix/osdrivers/objdrv_mysql.c index 4d5f2b004..95fbde63b 100755 --- a/centrallix/osdrivers/objdrv_mysql.c +++ b/centrallix/osdrivers/objdrv_mysql.c @@ -308,6 +308,19 @@ mysd_internal_GetConn(pMysdNode node) nmFree(conn, sizeof(MysdConn)); return NULL; } + + int ret, err; + char csname [] = "utf8"; + ret = mysql_set_character_set(&conn, csname); + if(ret != 0){ + // failure + perror("character set not set to utf8"); + err = mysql_errno(); + } + + + + if (mysql_real_connect(&conn->Handle, node->Server, username, password, node->Database, 0, NULL, 0) == NULL) { if (node->Flags & MYSD_NODE_F_SETCXAUTH) @@ -366,7 +379,28 @@ mysd_internal_GetConn(pMysdNode node) return conn; } +/* + +size_t strlen_mb(char * st){ + + size_t res = 0; + const char * start = s; + const char * end = start + strlen(s); + mblen(NULL,0); + while(ptr < end){ + int next = mblen(start, end-start); + if(next == -1){ + perror("conversion error"); + } + ptr += next; + result++; + } + return result; + + + +*/ /*** mysd_internal_ReleaseConn() - release a connection back to the connection *** pool. Also sets the pointer to NULL. @@ -2097,7 +2131,10 @@ mysd_internal_TreeToClause(pExpression tree, pMysdTable *tdata, pXString where_c ** the first subexpression we find out that it is a string. After all, ** this needs to work, but it doesn't need to look pretty. **/ - i = strlen(where_clause->String); + + // need to use a multibyte strlen + i = strlen(where_clause->String); + // i = mblen(where_clause->String, strlen(where_clause->String)); xsConcatenate(where_clause, " (", -1); mysd_internal_TreeToClause(subtree, tdata, where_clause,conn); if (subtree->DataType == DATA_T_STRING) From 15b5cb9e9238cac97171bf91b0bbbcd6ee3d40f9 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Wed, 8 Jul 2020 09:48:07 -0600 Subject: [PATCH 034/124] UTF-8 upper and lower --- centrallix/tests/test_expfn_utf8lower_00.cmp | 38 ++++++++++++++++++++ centrallix/tests/test_expfn_utf8lower_00.to | 14 +++++++- centrallix/tests/test_expfn_utf8upper_00.cmp | 38 ++++++++++++++++++++ centrallix/tests/test_expfn_utf8upper_00.to | 12 ++++++- 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100755 centrallix/tests/test_expfn_utf8lower_00.cmp create mode 100755 centrallix/tests/test_expfn_utf8upper_00.cmp diff --git a/centrallix/tests/test_expfn_utf8lower_00.cmp b/centrallix/tests/test_expfn_utf8lower_00.cmp new file mode 100755 index 000000000..d4fba4443 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8lower_00.cmp @@ -0,0 +1,38 @@ +Attribute [column_000]: string "test" +Attribute [column_000]: string "" +Attribute [column_000]: string "this is a longer test" +Attribute [column_000]: string "" +Attribute [column_000]: string "'" +Attribute [column_000]: string "100" +Attribute [column_000]: string "/" +Attribute [column_000]: string "short test" +Attribute [column_000]: string "" +Attribute [column_000]: string "test" +Attribute [column_000]: string "this is a much longer test string" +Attribute [column_000]: string "test" +Attribute [column_000]: string "" +Attribute [column_000]: string "this is a longer test" +Attribute [column_000]: string "short test" +Attribute [column_000]: string "a medium test" +Attribute [column_000]: string "black" +Attribute [column_000]: string "white" +Attribute [column_000]: string "grey" +Attribute [column_000]: string "charcoal" +Attribute [column_000]: string "green" +Attribute [column_000]: string "yellow" +Attribute [column_000]: string "red" +Attribute [column_000]: string "blue" +Attribute [column_000]: string "purple" +Attribute [column_000]: string "orange" +Attribute [column_000]: string "violet" +Attribute [column_000]: string NULL +Attribute [column_000]: string " " +Attribute [column_000]: string "española" +Attribute [column_000]: string "română" +Attribute [column_000]: string "日本人" +Attribute [column_000]: string "српски" +Attribute [column_000]: string "монгол" +Attribute [column_000]: string "ελληνικά" +Attribute [column_000]: string "ελληνικά" +Attribute [column_000]: string "français" +Attribute [column_000]: string "ﺭ" diff --git a/centrallix/tests/test_expfn_utf8lower_00.to b/centrallix/tests/test_expfn_utf8lower_00.to index 386819690..9465bbd57 100644 --- a/centrallix/tests/test_expfn_utf8lower_00.to +++ b/centrallix/tests/test_expfn_utf8lower_00.to @@ -1,6 +1,18 @@ -##NAME lower() function +##NAME UTF-8 lower() function query select lower(:f_string) from /tests/Datatypes.csv/rows query select lower(:Color) from /tests/TestLevel1.csv/rows query select lower(null) query select lower("\t") +query select lower("ESPAÑOLA") +query select lower("ROMÂNĂ") +query select lower("日本人") +query select lower("СРПСКИ") +query select lower("МОНГОЛ") +query select lower("ΕΛΛΗΝΙΚΆ") +query select lower("Ελληνικά") +query select lower("FRANÇAIS") +query select lower("ﺭ") + + + diff --git a/centrallix/tests/test_expfn_utf8upper_00.cmp b/centrallix/tests/test_expfn_utf8upper_00.cmp new file mode 100755 index 000000000..4349f3cd2 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8upper_00.cmp @@ -0,0 +1,38 @@ +Attribute [column_000]: string "TEST" +Attribute [column_000]: string "" +Attribute [column_000]: string "THIS IS A LONGER TEST" +Attribute [column_000]: string "" +Attribute [column_000]: string "'" +Attribute [column_000]: string "100" +Attribute [column_000]: string "/" +Attribute [column_000]: string "SHORT TEST" +Attribute [column_000]: string "" +Attribute [column_000]: string "TEST" +Attribute [column_000]: string "THIS IS A MUCH LONGER TEST STRING" +Attribute [column_000]: string "TEST" +Attribute [column_000]: string "" +Attribute [column_000]: string "THIS IS A LONGER TEST" +Attribute [column_000]: string "SHORT TEST" +Attribute [column_000]: string "A MEDIUM TEST" +Attribute [column_000]: string "BLACK" +Attribute [column_000]: string "WHITE" +Attribute [column_000]: string "GREY" +Attribute [column_000]: string "CHARCOAL" +Attribute [column_000]: string "GREEN" +Attribute [column_000]: string "YELLOW" +Attribute [column_000]: string "RED" +Attribute [column_000]: string "BLUE" +Attribute [column_000]: string "PURPLE" +Attribute [column_000]: string "ORANGE" +Attribute [column_000]: string "VIOLET" +Attribute [column_000]: string NULL +Attribute [column_000]: string " " +Attribute [column_000]: string "ESPAÑOLA" +Attribute [column_000]: string "ROMÂNĂ" +Attribute [column_000]: string "日本人" +Attribute [column_000]: string "СРПСКИ" +Attribute [column_000]: string "МОНГОЛ" +Attribute [column_000]: string "ΕΛΛΗΝΙΚΆ" +Attribute [column_000]: string "ΕΛΛΗΝΙΚΑ" +Attribute [column_000]: string "FRANÇAIS" +Attribute [column_000]: string "ر" diff --git a/centrallix/tests/test_expfn_utf8upper_00.to b/centrallix/tests/test_expfn_utf8upper_00.to index 7f6691f3b..e3ada24fe 100644 --- a/centrallix/tests/test_expfn_utf8upper_00.to +++ b/centrallix/tests/test_expfn_utf8upper_00.to @@ -1,6 +1,16 @@ -##NAME upper() function +##NAME utf8 upper() function query select upper(:f_string) from /tests/Datatypes.csv/rows query select upper(:Color) from /tests/TestLevel1.csv/rows query select upper(null) query select upper("\t") +query select upper("española") +query select upper("română") +query select upper("日本人") +query select upper("српски") +query select upper("монгол") +query select upper("Ελληνικά") +query select upper("ΕΛΛΗΝΙΚΑ") +query select upper("français") +query select upper("ر") + From 2e81f86e26d8db8309566c09ba88babd8bc4d585 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Wed, 8 Jul 2020 15:33:01 -0600 Subject: [PATCH 035/124] Progress on loading Kardia; done expfn_utf8substring --- centrallix-os/sys/js/htdrv_editbox.js | 5 ++++- centrallix/expression/exp_functions.c | 18 +++++++++++------ centrallix/netdrivers/net_http.c | 5 +++-- centrallix/osdrivers/objdrv_mysql.c | 3 ++- .../tests/test_expfn_utf8substring_00.cmp | 20 +++++++++++++++++++ .../tests/test_expfn_utf8substring_00.to | 8 ++++++++ 6 files changed, 49 insertions(+), 10 deletions(-) create mode 100755 centrallix/tests/test_expfn_utf8substring_00.cmp mode change 100644 => 100755 centrallix/tests/test_expfn_utf8substring_00.to diff --git a/centrallix-os/sys/js/htdrv_editbox.js b/centrallix-os/sys/js/htdrv_editbox.js index 66019b770..c68f78a3e 100644 --- a/centrallix-os/sys/js/htdrv_editbox.js +++ b/centrallix-os/sys/js/htdrv_editbox.js @@ -246,6 +246,7 @@ function eb_update(txt) function eb_paste(e) { + return; } @@ -273,13 +274,14 @@ function eb_receiving_input(e) changed = true; rend = curlen; } - if (k >= 32 && k < 127 || k > 127) + if ((e >= 32 && e < 127) || e > 127) { newtxt = cx_hints_checkmodify(l,txt,vistxt.substr(0,l.cursorCol) + String.fromCharCode(k) + vistxt.substr(l.cursorCol,vistxt.length), l._form_type); if (newtxt != txt) { cursoradj = 1; } + } if (rstart > curlen) { changed = true; @@ -321,6 +323,7 @@ function eb_receiving_input(e) return; } + function eb_keydown(e) diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 2cb5f63d9..8f74f1354 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -3476,7 +3476,7 @@ int exp_fn_nth(pExpression tree, pParamObjects objlist, pExpression i0, pExpress int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { size_t bufferLength = 64; - size_t initialPosition; + size_t initialPosition, substringLength; char * output; if (!i0 || !i1 || i0->Flags & EXPR_F_NULL || i1->Flags & EXPR_F_NULL) @@ -3495,17 +3495,23 @@ int exp_fn_utf8_substring(pExpression tree, pParamObjects objlist, pExpression i mssError(1, "EXP", "Invalid datatypes in substring() - takes (string,integer,[integer])"); return -1; } - + /** Free any previous string in preparation for these results **/ if (tree->Alloc && tree->String) { - nmSysFree(tree->String); + nmSysFree(tree->String); tree->Alloc = 0; } - tree->DataType = DATA_T_STRING; + + tree->DataType = DATA_T_STRING; - initialPosition = i1->Integer < 1 ? 0 : i1->Integer - 1; - output = chrSubstring(i0->String, initialPosition, i2->Integer < 0 ? 0 : i2->Integer + initialPosition, tree->Types.StringBuf, &bufferLength); + initialPosition = i1->Integer < 1 ? 0 : i1->Integer - 1; + if (i2) + substringLength = i2->Integer < 0 ? 0 : i2->Integer + initialPosition; + else + substringLength = strlen(i0->String); + + output = chrSubstring(i0->String, initialPosition, substringLength, tree->Types.StringBuf, &bufferLength); if(output) { diff --git a/centrallix/netdrivers/net_http.c b/centrallix/netdrivers/net_http.c index cbbde6cf9..148249f9f 100755 --- a/centrallix/netdrivers/net_http.c +++ b/centrallix/netdrivers/net_http.c @@ -821,7 +821,7 @@ nht_i_WriteResponse(pNhtConn conn, int code, char* text, char* resptxt) "Date: %STR\r\n" "%[Set-Cookie: %STR; path=/; HttpOnly%]%[; Secure%]%[; SameSite=strict%]%[\r\n%]" "%[Content-Length: %INT\r\n%]" - "%[Content-Type: %STR\r\n%]" + "%[Content-Type: text/html; charset=%STR\r\n%]" "%[Pragma: %STR\r\n%]" "%[Transfer-Encoding: chunked\r\n%]" "Referrer-Policy: same-origin\r\n" @@ -2044,7 +2044,8 @@ nht_i_GET(pNhtConn conn, pStruct url_inf, char* if_modified_since) } /** Print encoding type and content type **/ - fdPrintf(conn->ConnFD,"Content-Type: text/html; charset=%s\r\nPragma: no-cache\r\n\r\n", chrGetEquivalentName("http")); + //This is causing Kardia to not load + //fdPrintf(conn->ConnFD,"Content-Type: text/html; charset=%s\r\nPragma: no-cache\r\n\r\n", chrGetEquivalentName("http")); /** Send the response **/ conn->NoCache = 1; diff --git a/centrallix/osdrivers/objdrv_mysql.c b/centrallix/osdrivers/objdrv_mysql.c index 95fbde63b..75d03d384 100755 --- a/centrallix/osdrivers/objdrv_mysql.c +++ b/centrallix/osdrivers/objdrv_mysql.c @@ -315,7 +315,8 @@ mysd_internal_GetConn(pMysdNode node) if(ret != 0){ // failure perror("character set not set to utf8"); - err = mysql_errno(); + //needs an argument + //err = mysql_errno(); } diff --git a/centrallix/tests/test_expfn_utf8substring_00.cmp b/centrallix/tests/test_expfn_utf8substring_00.cmp new file mode 100755 index 000000000..49e16eb04 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8substring_00.cmp @@ -0,0 +1,20 @@ +Attribute [column_000]: string "cd" +Attribute [column_000]: string "de" +Attribute [column_000]: string "abcde" +Attribute [column_000]: string "ab" +Attribute [column_000]: string "c" +Attribute [column_000]: string "" +Attribute [column_000]: string NULL +Attribute [column_000]: string NULL +Attribute [column_000]: string "string" +Attribute [column_000]: string "y longer string" +Attribute [column_000]: string "\\" +Attribute [column_000]: string "" +Attribute [column_000]: string "ラ" +Attribute [column_000]: string "イト" +Attribute [column_000]: string "χ" +Attribute [column_000]: string "" +Attribute [column_000]: string "СРПСКИ" +Attribute [column_000]: string "ΛΛ" +Attribute [column_000]: string "hello" +Attribute [column_000]: string "ﺭ" diff --git a/centrallix/tests/test_expfn_utf8substring_00.to b/centrallix/tests/test_expfn_utf8substring_00.to old mode 100644 new mode 100755 index 6bc01b616..7869a16c7 --- a/centrallix/tests/test_expfn_utf8substring_00.to +++ b/centrallix/tests/test_expfn_utf8substring_00.to @@ -12,3 +12,11 @@ query select substring("string", 1) query select substring("a slightly longer string", 10, 50) query select substring("\\", 1, 1) query select substring("", 1, 1) +query select substring("ライト", 1, 1) +query select substring("ライト", 2) +query select substring("χ", -10000) +query select substring("χ", 3) +query select substring("bufferСРПСКИbuffer", 7, 6) +query select substring("ΕΛΛΗΝΙΚΑ", 2, 2) +query select substring("МОНhelloГОЛ", 4, 5) +query select substring("日ﺭ本人", 2, 1) From a37f7ea054ae2826b0d7eda0b2f8bd508e14cba6 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Wed, 8 Jul 2020 16:09:04 -0600 Subject: [PATCH 036/124] Kardia works normally --- centrallix-os/sys/js/htdrv_editbox.js | 1 - 1 file changed, 1 deletion(-) diff --git a/centrallix-os/sys/js/htdrv_editbox.js b/centrallix-os/sys/js/htdrv_editbox.js index c68f78a3e..5c18e60a2 100644 --- a/centrallix-os/sys/js/htdrv_editbox.js +++ b/centrallix-os/sys/js/htdrv_editbox.js @@ -246,7 +246,6 @@ function eb_update(txt) function eb_paste(e) { - return; } From c4b78130801ed670c4a93587ddec1f4fc49c830d Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Fri, 10 Jul 2020 06:20:00 -0600 Subject: [PATCH 037/124] All 12 expfn utf8 fcns pass --- centrallix/expression/exp_functions.c | 109 ++---------------- centrallix/tests/test_expfn_ascii_01.cmp | 6 - centrallix/tests/test_expfn_ascii_01.to | 13 --- centrallix/tests/test_expfn_utf8ascii_00.cmp | 26 +++++ centrallix/tests/test_expfn_utf8ascii_00.to | 22 +++- .../tests/test_expfn_utf8charindex_00.cmp | 41 +++++++ .../tests/test_expfn_utf8charindex_00.to | 84 +++++++------- .../tests/test_expfn_utf8charlength_00.cmp | 32 ++--- .../tests/test_expfn_utf8charlength_00.to | 16 +-- centrallix/tests/test_expfn_utf8escape_00.cmp | 9 ++ centrallix/tests/test_expfn_utf8escape_00.to | 19 +++ centrallix/tests/test_expfn_utf8lower_00.to | 2 +- centrallix/tests/test_expfn_utf8ralign_00.cmp | 30 +++++ centrallix/tests/test_expfn_utf8ralign_00.to | 19 ++- centrallix/tests/test_expfn_utf8replace_00.to | 2 +- .../tests/test_expfn_utf8reverse_00.cmp | 2 +- centrallix/tests/test_expfn_utf8reverse_00.to | 10 +- centrallix/tests/test_expfn_utf8right_00.cmp | 16 +++ centrallix/tests/test_expfn_utf8right_00.to | 17 ++- centrallix/tests/test_expfn_utf8sub_00.to | 2 +- .../tests/test_expfn_utf8substring_00.to | 2 +- centrallix/tests/test_expfn_utf8upper_00.to | 2 +- centrallix/utility/charsets.c | 14 +-- 23 files changed, 284 insertions(+), 211 deletions(-) delete mode 100644 centrallix/tests/test_expfn_ascii_01.cmp delete mode 100644 centrallix/tests/test_expfn_ascii_01.to create mode 100755 centrallix/tests/test_expfn_utf8ascii_00.cmp create mode 100755 centrallix/tests/test_expfn_utf8charindex_00.cmp create mode 100755 centrallix/tests/test_expfn_utf8escape_00.cmp create mode 100644 centrallix/tests/test_expfn_utf8escape_00.to create mode 100755 centrallix/tests/test_expfn_utf8ralign_00.cmp create mode 100755 centrallix/tests/test_expfn_utf8right_00.cmp diff --git a/centrallix/expression/exp_functions.c b/centrallix/expression/exp_functions.c index 8f74f1354..6ac34ce53 100755 --- a/centrallix/expression/exp_functions.c +++ b/centrallix/expression/exp_functions.c @@ -1024,8 +1024,6 @@ int exp_fn_right(pExpression tree, pParamObjects objlist, pExpression i0, pExpre int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - printf("Substring\n"); - fflush(stdout); int i,n; char* ptr; @@ -1045,21 +1043,16 @@ int exp_fn_substring(pExpression tree, pParamObjects objlist, pExpression i0, pE mssError(1,"EXP","Invalid datatypes in substring() - takes (string,integer,[integer])"); return -1; } - printf("Passed\n"); - printf("String: %s\n", i0->String); - fflush(stdout); + n = strlen(i0->String); i = i1->Integer-1; if (i<0) i = 0; if (i > n) i = n; - ptr = i0->String + i; - printf("Indexed string: %s\n", ptr); - fflush(stdout); + ptr = i0->String + i; i = i2?(i2->Integer):(strlen(ptr)); if (i < 0) i = 0; if (i > strlen(ptr)) i = strlen(ptr); - printf("Num chars: %d", i); - fflush(stdout); + /** Ok, got position and length. Now make new string in tree-> **/ if (tree->Alloc && tree->String) { @@ -3239,16 +3232,16 @@ int exp_fn_last(pExpression tree, pParamObjects objlist, pExpression i0, pExpres int exp_fn_utf8_overlong(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) { - printf("EXP\nRecieved String: %s\n", i0->String); + //printf("EXP\nRecieved String: %s\n", i0->String); char* str = chrNoOverlong(i0->String); - printf("A"); - fflush(stdout); - printf("Final str: %s\n", str); - printf("B"); - fflush(stdout); + //printf("A"); + //fflush(stdout); + //printf("Final str: %s\n", str); + //printf("B"); + //fflush(stdout); tree->String = str; - printf("C"); - fflush(stdout); + //printf("C"); + //fflush(stdout); return 0; } @@ -3734,81 +3727,6 @@ int exp_fn_utf8_reverse(pExpression tree, pParamObjects objlist, pExpression i0, return 0; } -/*int exp_fn_utf8_replace(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - printf("Starting\n"); - char *haystack, *needle, *replace; - long long newsize, diff; - char* pos; - char *dstptr, *oldptr; - size_t len_replace, len_needle, len_haystack, num_shifts; - - if ((i0 && (i0->Flags & EXPR_F_NULL)) || (i1 && (i1->Flags & EXPR_F_NULL))) - { - tree->Flags |= EXPR_F_NULL; - tree->DataType = DATA_T_STRING; - return 0; - } - if (!i0 || i0->DataType != DATA_T_STRING || !i1 || i1->DataType != DATA_T_STRING || !i2 || (!(i2->Flags & EXPR_F_NULL) && i2->DataType != DATA_T_STRING)) - { mssError(1,"EXP","replace() expects three string parameters (str,search,replace)"); - return -1; - } - if (i2->Flags & EXPR_F_NULL) - replace = ""; - else - replace = i2->String; - - if (tree->Alloc && tree->String) - nmSysFree(tree->String); - tree->Alloc = 0; - if (i1->String[0] == '\0') - { - tree->String = i0->String; - return 0; - } - printf("Passed init stuff\n"); - fflush(stdout); - haystack = i0->String; - needle = i1->String; - printf("strcpy\n"); - len_haystack = strlen(haystack); - len_needle = strlen(needle); - len_replace = strlen(replace); - printf("lens\n"); - fflush(stdout); - dstptr = nmSysMalloc((len_haystack + 1) * sizeof(char)); - strcpy(dstptr, haystack); - printf("malloc\n"); - fflush(stdout); - pos = strstr(haystack, needle); - while(pos != NULL) - { - printf("Start while\n"); - fflush(stdout); - oldptr = dstptr; - len_haystack = strlen(dstptr); - diff = (long long) (len_replace - len_needle); - dstptr = nmSysMalloc((len_haystack + diff + 1) * sizeof(char)); - - num_shifts = pos - oldptr; - memcpy(dstptr, oldptr, num_shifts); - memcpy(dstptr + num_shifts, replace, len_replace); - memcpy(dstptr + num_shifts + len_replace, pos + len_needle, len_haystack + 1 - num_shifts - len_needle); - - //free(oldptr); - pos = strstr(haystack, needle); - } - - strcpy(tree->String, dstptr); - return 0; - } - -int exp_fn_utf8_substitute(pExpression tree, pParamObjects objlist, pExpression i0, pExpression i1, pExpression i2) - { - return 0; - } -*/ - int exp_internal_DefineFunctions() { @@ -3874,10 +3792,6 @@ exp_internal_DefineFunctions() xhAdd(&EXP.ReverseFunctions, "isnull", (char*) exp_fn_reverse_isnull); /** UTF-8/ASCII dependent **/ - xhAdd(&EXP.Functions, "utf8_reverse", (char*) exp_fn_utf8_reverse); - xhAdd(&EXP.Functions, "overlong", (char*) exp_fn_utf8_overlong); - xhAdd(&EXP.Functions, "utf8_charindex", (char*) exp_fn_utf8_charindex); - xhAdd(&EXP.Functions, "utf8_char_length", (char*) exp_fn_utf8_char_length); if (CxGlobals.CharacterMode == CharModeSingleByte) { xhAdd(&EXP.Functions, "substring", (char*) exp_fn_substring); @@ -3903,6 +3817,7 @@ exp_internal_DefineFunctions() xhAdd(&EXP.Functions, "ralign", (char*) exp_fn_utf8_ralign); xhAdd(&EXP.Functions, "escape", (char*) exp_fn_utf8_escape); xhAdd(&EXP.Functions, "reverse", (char*) exp_fn_utf8_reverse); + xhAdd(&EXP.Functions, "overlong", (char*) exp_fn_utf8_overlong); } return 0; diff --git a/centrallix/tests/test_expfn_ascii_01.cmp b/centrallix/tests/test_expfn_ascii_01.cmp deleted file mode 100644 index bf372b837..000000000 --- a/centrallix/tests/test_expfn_ascii_01.cmp +++ /dev/null @@ -1,6 +0,0 @@ -Attribute [ascii("God")]: integer 71 -Attribute [ascii("-3")]: integer 45 -Attribute [ascii("È")]: integer null -Attribute [ascii("À")]: integer null -Attribute [ascii("Ç")]: integer null -Attribute [ascii("Ô")]: integer null diff --git a/centrallix/tests/test_expfn_ascii_01.to b/centrallix/tests/test_expfn_ascii_01.to deleted file mode 100644 index e088bd94d..000000000 --- a/centrallix/tests/test_expfn_ascii_01.to +++ /dev/null @@ -1,13 +0,0 @@ -##NAME ascii() function -# Will not be as expected because no support for utf-8 yet -query select 'ascii("God")' = ascii("God") - -query select 'ascii("-3")' = ascii("-3") - -query select 'ascii("È")' = ascii("È") - -query select 'ascii("À")' = ascii("À") - -query select 'ascii("Ç")' = ascii("Ç") - -query select 'ascii("Ô")' = ascii("Ô") diff --git a/centrallix/tests/test_expfn_utf8ascii_00.cmp b/centrallix/tests/test_expfn_utf8ascii_00.cmp new file mode 100755 index 000000000..3a0a27597 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8ascii_00.cmp @@ -0,0 +1,26 @@ +Attribute [ascii("A")]: integer 65 +Attribute [ascii("Ab")]: integer 65 +Attribute [ascii("1")]: integer 49 +Attribute [ascii("10")]: integer 49 +Attribute [ascii(null)]: integer NULL +Attribute [ascii("")]: integer NULL +Attribute [ascii("a", "b", "c", "d")]: integer 97 +Attribute [ascii("God")]: integer 71 +Attribute [ascii("-3")]: integer 45 +Attribute [ascii("È")]: integer 200 +Attribute [ascii("À")]: integer 192 +Attribute [ascii("Ç")]: integer 199 +Attribute [ascii("Ô")]: integer 212 +Attribute [ascii("0")]: integer 48 +Attribute [ascii("\")]: integer 92 +Attribute [ascii("本")]: integer 26412 +Attribute [ascii("日")]: integer 26085 +Attribute [ascii("人")]: integer 20154 +Attribute [ascii("Λ")]: integer 923 +Attribute [ascii("Ñ")]: integer 209 +Attribute [ascii("ﻡ")]: integer 65249 +Attribute [ascii("ﺢ")]: integer 65186 +Attribute [ascii("ρ")]: integer 961 +Attribute [ascii("χ")]: integer 967 +Attribute [ascii("М")]: integer 1052 +Attribute [ascii("МОНГОЛ ]: integer 1052 diff --git a/centrallix/tests/test_expfn_utf8ascii_00.to b/centrallix/tests/test_expfn_utf8ascii_00.to index 3fa90b0b7..29a8739e8 100644 --- a/centrallix/tests/test_expfn_utf8ascii_00.to +++ b/centrallix/tests/test_expfn_utf8ascii_00.to @@ -1,4 +1,4 @@ -##NAME ascii() function +##NAME UTF-8 compatible ascii() function query select 'ascii("A")' = ascii("A") query select 'ascii("Ab")' = ascii("Ab") @@ -6,3 +6,23 @@ query select 'ascii("1")' = ascii("1") query select 'ascii("10")' = ascii("10") query select 'ascii(null)' = ascii(null) query select 'ascii("")' = ascii("") +query select 'ascii("a", "b", "c", "d")' = ascii("a", "b", "c", "d") +query select 'ascii("God")' = ascii("God") +query select 'ascii("-3")' = ascii("-3") +query select 'ascii("È")' = ascii("È") +query select 'ascii("À")' = ascii("À") +query select 'ascii("Ç")' = ascii("Ç") +query select 'ascii("Ô")' = ascii("Ô") +query select 'ascii("\0")' = ascii("\0") +query select 'ascii("\\")' = ascii("\\") +query select 'ascii("本")' = ascii("本") +query select 'ascii("日")' = ascii("日") +query select 'ascii("人")' = ascii("人") +query select 'ascii("Λ")' = ascii("Λ") +query select 'ascii("Ñ")' = ascii("Ñ") +query select 'ascii("ﻡ")' = ascii("ﻡ") +query select 'ascii("ﺢ")' = ascii("ﺢ") +query select 'ascii("ρ")' = ascii("ρ") +query select 'ascii("χ")' = ascii("χ") +query select 'ascii("М")' = ascii("М") +query select 'ascii("МОНГОЛ МОНГОЛ")' = ascii("МОНГОЛ МОНГОЛ") diff --git a/centrallix/tests/test_expfn_utf8charindex_00.cmp b/centrallix/tests/test_expfn_utf8charindex_00.cmp new file mode 100755 index 000000000..dbd075a82 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8charindex_00.cmp @@ -0,0 +1,41 @@ +Attribute [charindex("abc", "abcdefg")]: integer 1 +Attribute [charindex("abc", "abcdefghijklm]: integer 1 +Attribute [charindex("cde", "abcdefg")]: integer 3 +Attribute [charindex("efg", "abcdefg")]: integer 5 +Attribute [charindex("fgh", "abcdefg")]: integer 0 +Attribute [charindex("1ab", "abcdefg")]: integer 0 +Attribute [charindex("a", "abcdefg")]: integer 1 +Attribute [charindex("d", "abcdefg")]: integer 4 +Attribute [charindex("g", "abcdefg")]: integer 7 +Attribute [charindex("h", "abcdefg")]: integer 0 +Attribute [charindex("1", "abcdefg")]: integer 0 +Attribute [charindex("abc", "a")]: integer 0 +Attribute [charindex("abc", "abc")]: integer 1 +Attribute [charindex("", "abcdefg")]: integer 1 +Attribute [charindex("a", "")]: integer 0 +Attribute [charindex("", "")]: integer 1 +Attribute [charindex(null, "abcdefg")]: integer NULL +Attribute [charindex("a", null)]: integer NULL +Attribute [charindex(null, null)]: integer NULL +Attribute [charindex("", null)]: integer NULL +Attribute [charindex(null, "")]: integer NULL +Attribute [charindex("δα", "ελπίδα]: integer 5 +Attribute [charindex("s", "Adiós")]: integer 5 +Attribute [charindex("Glück", "Glück")]: integer 1 +Attribute [charindex("АДЖИ", "АДЖN"]: integer 0 +Attribute [charindex("Ж", "АДЖИ")]: integer 3 +Attribute [charindex("rançai", "français]: integer 2 +Attribute [charindex("ạs", "Swạs")]: integer 3 +Attribute [charindex("a", "Swạs")]: integer 0 +Attribute [charindex("Сал", "Салом]: integer 1 +Attribute [charindex("", "Салом")]: integer 1 +Attribute [charindex("Салом", "")]: integer 0 +Attribute [charindex("", "χ")]: integer 1 +Attribute [charindex("ά", "ρά")]: integer 2 +Attribute [charindex(" ", "ρ ά ")]: integer 2 +Attribute [charindex("ρά", null)]: integer NULL +Attribute [charindex("χ", "χ")]: integer 1 +Attribute [charindex("лж ба", "бар]: integer 8 +Attribute [charindex("!^&*", "!$%!^&^*!^&*]: integer 9 +Attribute [charindex(null, "ДЖ")]: integer NULL +Attribute [charindex("5", "123456789")]: integer 5 diff --git a/centrallix/tests/test_expfn_utf8charindex_00.to b/centrallix/tests/test_expfn_utf8charindex_00.to index cffa6e707..987c337e3 100644 --- a/centrallix/tests/test_expfn_utf8charindex_00.to +++ b/centrallix/tests/test_expfn_utf8charindex_00.to @@ -1,45 +1,47 @@ -##NAME charindex() function +##NAME UTF-8 compatible charindex() function -query select 'utf8_charindex("abc", "abcdefg")' = utf8_charindex("abc", "abcdefg") -query select 'utf8_charindex("abc", "abcdefghijklmnopqrstuvwxyz")' = utf8_charindex("abc", "abcdefghijklmnopqrstuvwxyz") -query select 'utf8_charindex("cde", "abcdefg")' = utf8_charindex("cde", "abcdefg") -query select 'utf8_charindex("efg", "abcdefg")' = utf8_charindex("efg", "abcdefg") -query select 'utf8_charindex("fgh", "abcdefg")' = utf8_charindex("fgh", "abcdefg") -query select 'utf8_charindex("1ab", "abcdefg")' = utf8_charindex("1ab", "abcdefg") -query select 'utf8_charindex("a", "abcdefg")' = utf8_charindex("a", "abcdefg") -query select 'utf8_charindex("d", "abcdefg")' = utf8_charindex("d", "abcdefg") -query select 'utf8_charindex("g", "abcdefg")' = utf8_charindex("g", "abcdefg") -query select 'utf8_charindex("h", "abcdefg")' = utf8_charindex("h", "abcdefg") -query select 'utf8_charindex("1", "abcdefg")' = utf8_charindex("1", "abcdefg") -query select 'utf8_charindex("abc", "a")' = utf8_charindex("abc", "a") -query select 'utf8_charindex("abc", "abc")' = utf8_charindex("abc", "abc") -query select 'utf8_charindex("", "abcdefg")' = utf8_charindex("", "abcdefg") -query select 'utf8_charindex("a", "")' = utf8_charindex("a", "") -query select 'utf8_charindex("", "")' = utf8_charindex("", "") -query select 'utf8_charindex(null, "abcdefg")' = utf8_charindex(null, "abcdefg") -query select 'utf8_charindex("a", null)' = utf8_charindex("a", null) -query select 'utf8_charindex(null, null)' = utf8_charindex(null, null) -query select 'utf8_charindex("", null)' = utf8_charindex("", null) -query select 'utf8_charindex(null, "")' = utf8_charindex(null, "") -query select 'utf8_charindex(:Full, :Part) from /tests/Foreign2.csv/rows' = utf8_charindex(:Full, :Part) from /tests/Foreign2.csv/rows -#query select 'utf8_charindex("ελπίδα", "δα")' = utf8_charindex("ελπίδα", "δα") -#query select 'utf8_charindex("Adiós", "s")' = charindex("Adiós", "s") -#query select 'utf8_charindex("Glück", "Glück")' = charindex("Glück", "Glück") -#query select 'utf8_charindex("АДЖИ", "N")' = charindex("АДЖИ", "N") -#query select 'utf8_charindex("français", "rançai")' = charindex("français", "rançai") -#query select 'utf8_charindex("Swạsdī", i")' = charindex("Swạsdī","i") -#query select 'utf8_charindex("a", "Swạs")' = charindex("a", "Swạs") -#query select 'utf8_charindex("Салом", "Сал")' = charindex("Салом", "Сал") -#query select 'utf8_charindex("Салом", "")' = charindex("Салом", "") -#query select 'utf8_charindex("", "χ")' = charindex("", "χ") -#query select 'utf8_charindex("ρά", "ά")' = charindex("ρά", "ά") -#query select 'utf8_charindex("ρά", "p")' = charindex("ρά", "ρά") -#query select 'utf8_charindex("ρά", null)' = charindex("ρά", null) -#query select 'utf8_charindex("χ", "χ")' = charindex("χ", "χ") -#query select 'utf8_charindex("баривчилж байна", "лж ба")' = charindex("баривчилж байна", "лж ба") -#query select 'utf8_charindex("!$%!^&^*!^&*", "!^&*")' = charindex("!$%!^&^*!^&*", "!^&*") -#query select 'utf8_charindex(null, "ДЖ")' = charindex(null, "ДЖ") -#query select 'utf8_charindex("123456789", "5")' = charindex("123456789", "5") +query select 'charindex("abc", "abcdefg")' = charindex("abc", "abcdefg") +query select 'charindex("abc", "abcdefghijklmnopqrstuvwxyz")' = charindex("abc", "abcdefghijklmnopqrstuvwxyz") +query select 'charindex("cde", "abcdefg")' = charindex("cde", "abcdefg") +query select 'charindex("efg", "abcdefg")' = charindex("efg", "abcdefg") +query select 'charindex("fgh", "abcdefg")' = charindex("fgh", "abcdefg") +query select 'charindex("1ab", "abcdefg")' = charindex("1ab", "abcdefg") +query select 'charindex("a", "abcdefg")' = charindex("a", "abcdefg") +query select 'charindex("d", "abcdefg")' = charindex("d", "abcdefg") +query select 'charindex("g", "abcdefg")' = charindex("g", "abcdefg") +query select 'charindex("h", "abcdefg")' = charindex("h", "abcdefg") +query select 'charindex("1", "abcdefg")' = charindex("1", "abcdefg") +query select 'charindex("abc", "a")' = charindex("abc", "a") +query select 'charindex("abc", "abc")' = charindex("abc", "abc") +query select 'charindex("", "abcdefg")' = charindex("", "abcdefg") +query select 'charindex("a", "")' = charindex("a", "") +query select 'charindex("", "")' = charindex("", "") +query select 'charindex(null, "abcdefg")' = charindex(null, "abcdefg") +query select 'charindex("a", null)' = charindex("a", null) +query select 'charindex(null, null)' = charindex(null, null) +query select 'charindex("", null)' = charindex("", null) +query select 'charindex(null, "")' = charindex(null, "") +#query select 'charindex(:r:Full, :r:Part) from /tests/Foreign2.csv/rows r' = charindex(:r:Full, :r:Part) from /tests/Foreign2.csv/rows r +query select 'charindex("δα", "ελπίδα")' = charindex("δα", "ελπίδα") +query select 'charindex("s", "Adiós")' = charindex("s", "Adiós") +query select 'charindex("Glück", "Glück")' = charindex("Glück", "Glück") +query select 'charindex("АДЖИ", "АДЖN")' = charindex("АДЖИ", "АДЖN") +query select 'charindex("Ж", "АДЖИ")' = charindex("Ж", "АДЖИ") +query select 'charindex("rançai", "français")' = charindex("rançai", "français") +query select 'charindex("ạs", "Swạs")' = charindex("ạs", "Swạs") +query select 'charindex("a", "Swạs")' = charindex("a", "Swạs") +query select 'charindex("Сал", "Салом")' = charindex("Сал", "Салом") +query select 'charindex("", "Салом")' = charindex("", "Салом") +query select 'charindex("Салом", "")' = charindex("Салом", "") +query select 'charindex("", "χ")' = charindex("", "χ") +query select 'charindex("ά", "ρά")' = charindex("ά", "ρά") +query select 'charindex(" ", "ρ ά ")' = charindex(" ", "ρ ά ") +query select 'charindex("ρά", null)' = charindex("ρά", null) +query select 'charindex("χ", "χ")' = charindex("χ", "χ") +query select 'charindex("лж ба", "баривчилж байна")' = charindex("лж ба", "баривчилж байна") +query select 'charindex("!^&*", "!$%!^&^*!^&*")' = charindex("!^&*", "!$%!^&^*!^&*") +query select 'charindex(null, "ДЖ")' = charindex(null, "ДЖ") +query select 'charindex("5", "123456789")' = charindex("5", "123456789") diff --git a/centrallix/tests/test_expfn_utf8charlength_00.cmp b/centrallix/tests/test_expfn_utf8charlength_00.cmp index c6ab5446a..d7481d9d1 100755 --- a/centrallix/tests/test_expfn_utf8charlength_00.cmp +++ b/centrallix/tests/test_expfn_utf8charlength_00.cmp @@ -1,16 +1,16 @@ -Attribute [utf8_char_length("abc")]: integer 3 -Attribute [utf8_char_length("a")]: integer 1 -Attribute [utf8_char_length("")]: integer 0 -Attribute [utf8_char_length(null)]: integer NULL -Attribute [utf8_char_length("abcde"*999999]: integer 4999995 -Attribute [utf8_char_length("كتاب")]: integer 4 -Attribute [utf8_char_length(:String) from ]: integer 6 -Attribute [utf8_char_length(:String) from ]: integer 5 -Attribute [utf8_char_length(:String) from ]: integer 5 -Attribute [utf8_char_length(:String) from ]: integer 4 -Attribute [utf8_char_length(:String) from ]: integer 8 -Attribute [utf8_char_length(:String) from ]: integer 6 -Attribute [utf8_char_length(:String) from ]: integer 5 -Attribute [utf8_char_length(:String) from ]: integer 2 -Attribute [utf8_char_length(:String) from ]: integer 1 -Attribute [utf8_char_length(:String) from ]: integer 24 +Attribute [char_length("abc")]: integer 3 +Attribute [char_length("a")]: integer 1 +Attribute [char_length("")]: integer 0 +Attribute [char_length(null)]: integer NULL +Attribute [char_length("abcde"*999999)]: integer 4999995 +Attribute [char_length("كتاب")]: integer 4 +Attribute [char_length(:String) from /test]: integer 6 +Attribute [char_length(:String) from /test]: integer 5 +Attribute [char_length(:String) from /test]: integer 5 +Attribute [char_length(:String) from /test]: integer 4 +Attribute [char_length(:String) from /test]: integer 8 +Attribute [char_length(:String) from /test]: integer 6 +Attribute [char_length(:String) from /test]: integer 5 +Attribute [char_length(:String) from /test]: integer 2 +Attribute [char_length(:String) from /test]: integer 1 +Attribute [char_length(:String) from /test]: integer 24 diff --git a/centrallix/tests/test_expfn_utf8charlength_00.to b/centrallix/tests/test_expfn_utf8charlength_00.to index 52f9881a9..9926ba984 100644 --- a/centrallix/tests/test_expfn_utf8charlength_00.to +++ b/centrallix/tests/test_expfn_utf8charlength_00.to @@ -1,9 +1,9 @@ -##NAME char_length() function +##NAME UTF-8 compatible char_length() function -query select 'utf8_char_length("abc")' = char_length("abc") -query select 'utf8_char_length("a")' = char_length("a") -query select 'utf8_char_length("")' = char_length("") -query select 'utf8_char_length(null)' = char_length(null) -query select 'utf8_char_length("abcde"*999999)' = char_length("abcde" * 999999) -query select 'utf8_char_length("كتاب")' = char_length("كتاب") -query select 'utf8_char_length(:String) from /tests/Foreign.csv/rows' = utf8_char_length(:String) from /tests/Foreign.csv/rows +query select 'char_length("abc")' = char_length("abc") +query select 'char_length("a")' = char_length("a") +query select 'char_length("")' = char_length("") +query select 'char_length(null)' = char_length(null) +query select 'char_length("abcde"*999999)' = char_length("abcde" * 999999) +query select 'char_length("كتاب")' = char_length("كتاب") +query select 'char_length(:String) from /tests/Foreign.csv/rows' = char_length(:String) from /tests/Foreign.csv/rows diff --git a/centrallix/tests/test_expfn_utf8escape_00.cmp b/centrallix/tests/test_expfn_utf8escape_00.cmp new file mode 100755 index 000000000..f1e4ae5cc --- /dev/null +++ b/centrallix/tests/test_expfn_utf8escape_00.cmp @@ -0,0 +1,9 @@ +Attribute [escape("abcde", "f", "g")]: string "abcde" +Attribute [escape("abcde", "a")]: string "\\abcde" +Attribute [escape("aaaaa", "a")]: string "\\a\\a\\a\\a\\a" +Attribute [escape("this is a more compli]: string "\\this\\ is\\ a\\ more\\ \\ \\ complica\\ted\\ \\tes\\t" +Attribute [escape("The buffer size will ne]: string "Th\\e b\\uff\\er s\\iz\\e w\\ill n\\e\\ed t\\o \\incr\\e\\as\\e b\\ec\\a\\us\\e \\of \\esc\\ap\\ing." +Attribute [escape("{sl"a"sh}", ""}{", "\")]: string "\\{sl\\\"a\\\"sh\\}" +Attribute [escape("АДЖИ\drop日本人-]: string "АДЖ\\И\\\\drop日本人\\-\\-all" +Attribute [escape("χ", "χ")]: string "\\χ" +Attribute [escape("Салом", "омСл]: string "\\С\\а\\л\\о\\м" diff --git a/centrallix/tests/test_expfn_utf8escape_00.to b/centrallix/tests/test_expfn_utf8escape_00.to new file mode 100644 index 000000000..b86c0b052 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8escape_00.to @@ -0,0 +1,19 @@ +##NAME UTF-8 compatible escape() function + +query select 'escape("abcde", "a", "c")' = escape("abcde", "a", "c") +query select 'escape("abcde", "f", "e")' = escape("abcde", "f", "e") +query select 'escape("abcde")' = escape("abcde") +query select 'escape("abcde", "c", 4)' = escape("abcde", "c", 4) + +query select 'escape("abcde", "f", "g")' = escape("abcde", "f", "g") +query select 'escape("abcde", "a")' = escape("abcde", "a") +query select 'escape("aaaaa", "a")' = escape("aaaaa", "a") +query select 'escape("this is a more complicated test", "t t", "8")' = escape("this is a more complicated test", "t t", "8") +query select 'escape("The buffer size will need to increase because of escaping.", "aeiou")' = escape("The buffer size will need to increase because of escaping.", "aeiou") + +query select 'escape("\{sl\"a\"sh\}", "\"\}\{", "\\")' = escape("\{sl\"a\"sh\}", "\"\}\{", "\\") +query select 'escape("АДЖИ\\drop日本人--all", "И\-")' = escape("АДЖИ\\drop日本人--all", "И\-") +query select 'escape("χ", "χ")' = escape("χ", "χ") +query select 'escape("Салом", "омСла")' = escape("Салом", "омСла") + + diff --git a/centrallix/tests/test_expfn_utf8lower_00.to b/centrallix/tests/test_expfn_utf8lower_00.to index 9465bbd57..8106030e3 100644 --- a/centrallix/tests/test_expfn_utf8lower_00.to +++ b/centrallix/tests/test_expfn_utf8lower_00.to @@ -1,4 +1,4 @@ -##NAME UTF-8 lower() function +##NAME UTF-8 compatible lower() function query select lower(:f_string) from /tests/Datatypes.csv/rows query select lower(:Color) from /tests/TestLevel1.csv/rows diff --git a/centrallix/tests/test_expfn_utf8ralign_00.cmp b/centrallix/tests/test_expfn_utf8ralign_00.cmp new file mode 100755 index 000000000..90b5d1b4f --- /dev/null +++ b/centrallix/tests/test_expfn_utf8ralign_00.cmp @@ -0,0 +1,30 @@ +Attribute [ralign("Test", 10)]: string " Test" +Attribute [ralign("Test", 0)]: string "Test" +Attribute [ralign("Test", -50)]: string "Test" +Attribute [ralign("",5)]: string " " +Attribute [ralign(null,1)]: string NULL +Attribute [ralign("A", 1, 9)]: string "A" +Attribute [column_000]: string " test" +Attribute [column_000]: string " " +Attribute [column_000]: string "this is a longer test" +Attribute [column_000]: string " " +Attribute [column_000]: string " '" +Attribute [column_000]: string " 100" +Attribute [column_000]: string " /" +Attribute [column_000]: string " short test" +Attribute [column_000]: string " " +Attribute [column_000]: string " test" +Attribute [column_000]: string "this is a much longer test string" +Attribute [column_000]: string " test" +Attribute [column_000]: string " " +Attribute [column_000]: string "this is a longer test" +Attribute [column_000]: string " short test" +Attribute [column_000]: string " a medium test" +Attribute [ralign("Сынақ", 0)]: string "Сынақ" +Attribute [ralign("Testdə", 2)]: string "Testdə" +Attribute [ralign("Ölçek", 5)]: string "Ölçek" +Attribute [ralign("اختبار", 7)]: string " ﺎﺨﺘﺑﺍﺭ" +Attribute [ralign("测试", -4)]: string "测试" +Attribute [ralign("Prüfung", 20)]: string " Prüfung" +Attribute [ralign("テスト テスト テ]: string " テスト テスト テスト テスト" +Attribute [ralign(" 테스트", 15)]: string " 테스트" diff --git a/centrallix/tests/test_expfn_utf8ralign_00.to b/centrallix/tests/test_expfn_utf8ralign_00.to index 43775511f..ad8c7f469 100644 --- a/centrallix/tests/test_expfn_utf8ralign_00.to +++ b/centrallix/tests/test_expfn_utf8ralign_00.to @@ -1,14 +1,21 @@ -##NAME ralign() function - -query select 'ralign("Test", 5)' = ralign("Test", 10) +##NAME UTF-8 compatible ralign() function +query select 'ralign("Test", 10)' = ralign("Test", 10) query select 'ralign("Test", 0)' = ralign("Test", 0) - query select 'ralign("Test", -50)' = ralign("Test", -10) - query select 'ralign("",5)' = ralign("",5) - query select 'ralign(null,1)' = ralign(null,1) +query select 'ralign("A", null)' = ralign("A", null) +query select 'ralign("A", "A")' = ralign("A", "A") +query select 'ralign("A", 1, 9)' = ralign("A", 1, 9) query select ralign(:f_string,20) from /tests/Datatypes.csv/rows +query select 'ralign("Сынақ", 0)' = ralign("Сынақ", 0) +query select 'ralign("Testdə", 2)' = ralign("Testdə", 2) +query select 'ralign("Ölçek", 5)' = ralign("Ölçek", 5) +query select 'ralign("اختبار", 7)' = ralign("ﺎﺨﺘﺑﺍﺭ", 7) +query select 'ralign("测试", -4)' = ralign("测试", -4) +query select 'ralign("Prüfung", 20)' = ralign("Prüfung", 20) +query select 'ralign("テスト テスト テスト テスト", 100)' = ralign("テスト テスト テスト テスト", 100) +query select 'ralign(" 테스트", 15)' = ralign(" 테스트", 15) diff --git a/centrallix/tests/test_expfn_utf8replace_00.to b/centrallix/tests/test_expfn_utf8replace_00.to index e01c9669e..c57daec46 100644 --- a/centrallix/tests/test_expfn_utf8replace_00.to +++ b/centrallix/tests/test_expfn_utf8replace_00.to @@ -1,4 +1,4 @@ -##NAME utf8_replace() function +##NAME UTF-8 compatible replace() function query select replace("abcdefg","cd","x") query select replace("abcdefg","cd","xyz") diff --git a/centrallix/tests/test_expfn_utf8reverse_00.cmp b/centrallix/tests/test_expfn_utf8reverse_00.cmp index 0e617c616..e3469b79e 100755 --- a/centrallix/tests/test_expfn_utf8reverse_00.cmp +++ b/centrallix/tests/test_expfn_utf8reverse_00.cmp @@ -35,4 +35,4 @@ Attribute [column_000]: string "молаС" Attribute [column_000]: string "άρ" Attribute [column_000]: string "χ" Attribute [column_000]: string "анйаб жличвираб днэт дэт" -Attribute [utf8_reverse(null)]: string NULL +Attribute [reverse(null)]: string NULL diff --git a/centrallix/tests/test_expfn_utf8reverse_00.to b/centrallix/tests/test_expfn_utf8reverse_00.to index a474774a8..f7eea1858 100644 --- a/centrallix/tests/test_expfn_utf8reverse_00.to +++ b/centrallix/tests/test_expfn_utf8reverse_00.to @@ -1,6 +1,6 @@ -##NAME utf8_reverse() function +##NAME UTF-8 compatible reverse() function -query select utf8_reverse(:f_string) from /tests/Datatypes.csv/rows -query select utf8_reverse(:Color) from /tests/TestLevel1.csv/rows -query select utf8_reverse(:String) from /tests/Foreign.csv/rows -query select 'utf8_reverse(null)' = utf8_reverse(null) +query select reverse(:f_string) from /tests/Datatypes.csv/rows +query select reverse(:Color) from /tests/TestLevel1.csv/rows +query select reverse(:String) from /tests/Foreign.csv/rows +query select 'reverse(null)' = reverse(null) diff --git a/centrallix/tests/test_expfn_utf8right_00.cmp b/centrallix/tests/test_expfn_utf8right_00.cmp new file mode 100755 index 000000000..ba4db8187 --- /dev/null +++ b/centrallix/tests/test_expfn_utf8right_00.cmp @@ -0,0 +1,16 @@ +Attribute [right("abcde", 3)]: string "cde" +Attribute [right("abcde", 8)]: string "abcde" +Attribute [right("abcde", 0)]: string "" +Attribute [right("abcde"", 6)]: string "abcde\"" +Attribute [right("", 1)]: string "" +Attribute [right(null, null)]: string NULL +Attribute [right("abc", null)]: string NULL +Attribute [right(null, 7)]: string NULL +Attribute [right("баривчилж ба]: string "" +Attribute [right("баривчилж ба]: string "вчилж байна" +Attribute [right("日本人", 4)]: string "日本人" +Attribute [right("日本人", 2)]: string "本人" +Attribute [right("Glück ", 9)]: string "lück " +Attribute [right("ρά", 2)]: string "ρά" +Attribute [right("Swạsdī", 4]: string "ạsdī" +Attribute [right("ROMÂNĂ ]: string "Ă " diff --git a/centrallix/tests/test_expfn_utf8right_00.to b/centrallix/tests/test_expfn_utf8right_00.to index 9117eaad1..c244d3e65 100644 --- a/centrallix/tests/test_expfn_utf8right_00.to +++ b/centrallix/tests/test_expfn_utf8right_00.to @@ -1,13 +1,20 @@ -##NAME right() function +##NAME UTF-8 compatible right() function query select 'right("abcde", 3)' = right("abcde", 3) - query select 'right("abcde", 8)' = right("abcde", 8) - query select 'right("abcde", 0)' = right("abcde", 0) - query select 'right("abcde\"", 6)' = right("abcde\"", 6) - query select 'right("", 1)' = right("", 1) query select 'right(null, null)' = right(null, null) +query select 'right("abc", null)' = right("abc", null) +query select 'right(null, 7)' = right(null, 7) + +query select 'right("баривчилж байна", -2)' = right("баривчилж байна", -2) +query select 'right("баривчилж байна", 11)' = right("баривчилж байна", 11) +query select 'right("日本人", 4)' = right("日本人", 4) +query select 'right("日本人", 2)' = right("日本人", 2) +query select 'right("Glück ", 9)' = right("Glück ", 9) +query select 'right("ρά", 2)' = right("ρά", 2) +query select 'right("Swạsdī", 4' = right("Swạsdī", 4) +query select 'right("ROMÂNĂ ", 21)' = right("ROMÂNĂ ", 21) diff --git a/centrallix/tests/test_expfn_utf8sub_00.to b/centrallix/tests/test_expfn_utf8sub_00.to index 04c75d312..6fe798cb1 100644 --- a/centrallix/tests/test_expfn_utf8sub_00.to +++ b/centrallix/tests/test_expfn_utf8sub_00.to @@ -1,4 +1,4 @@ -##NAME UTF-8 substitute function() +##NAME UTF-8 compatible substitute() function # basic example query select substitute("Color: [:row:Color] | Group: [:row:ColorGroup]", "row=r") from /tests/TestLevel1.csv/rows/ r diff --git a/centrallix/tests/test_expfn_utf8substring_00.to b/centrallix/tests/test_expfn_utf8substring_00.to index 7869a16c7..0588543c6 100755 --- a/centrallix/tests/test_expfn_utf8substring_00.to +++ b/centrallix/tests/test_expfn_utf8substring_00.to @@ -1,4 +1,4 @@ -##NAME substring function +##NAME UTF-8 compatible substring() function query select substring("abcde", 3, 2) query select substring("abcde", 4) diff --git a/centrallix/tests/test_expfn_utf8upper_00.to b/centrallix/tests/test_expfn_utf8upper_00.to index e3ada24fe..0a70c9547 100644 --- a/centrallix/tests/test_expfn_utf8upper_00.to +++ b/centrallix/tests/test_expfn_utf8upper_00.to @@ -1,4 +1,4 @@ -##NAME utf8 upper() function +##NAME UTF-8 compatible upper() function query select upper(:f_string) from /tests/Datatypes.csv/rows query select upper(:Color) from /tests/TestLevel1.csv/rows diff --git a/centrallix/utility/charsets.c b/centrallix/utility/charsets.c index be4b67c27..27c002b13 100755 --- a/centrallix/utility/charsets.c +++ b/centrallix/utility/charsets.c @@ -324,7 +324,7 @@ size_t chrCharLength(char* string) char* chrNoOverlong(char* string) { - printf("No Overlong\nInit String: %s\n", string); + //printf("No Overlong\nInit String: %s\n", string); size_t stringCharLength, newStrByteLength; char* toReturn; wchar_t* longBuffer; @@ -338,14 +338,14 @@ char* chrNoOverlong(char* string) { return NULL; } - printf("Args checked\n"); + //printf("Args checked\n"); /** Create wchar_t buffer */ longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); if(!longBuffer) return NULL; mbstowcs(longBuffer, string, stringCharLength + 1); - printf("Made wide buffer\n"); - wprintf(L"Wide String: %ls\n, longBuffer"); + //printf("Made wide buffer\n"); + //wprintf(L"Wide String: %ls\n, longBuffer"); /** Convert back to MBS **/ newStrByteLength = wcstombs(NULL, longBuffer, 0); if(newStrByteLength == (size_t)-1) @@ -353,7 +353,7 @@ char* chrNoOverlong(char* string) nmSysFree(longBuffer); return NULL; } - printf("got size\n"); + //printf("got size\n"); toReturn = (char *)nmSysMalloc(newStrByteLength + 1); if(!toReturn) { @@ -362,9 +362,9 @@ char* chrNoOverlong(char* string) } wcstombs(toReturn, longBuffer, newStrByteLength + 1); - printf("String: %s\n", toReturn); + //printf("String: %s\n", toReturn); nmSysFree(longBuffer); - printf("Done\n"); + //printf("Done\n"); //nmSysFree(string); //good? return toReturn; } From 402e8ec444456997cdfa12769f8a723530386660 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Fri, 10 Jul 2020 15:34:57 -0600 Subject: [PATCH 038/124] Minor Fixes --- centrallix-lib/src/xstring.c | 15 ++++++++++++-- centrallix-lib/tests/test_xstring_00.c | 27 ++++++++++++++++++++++++++ centrallix/osdrivers/objdrv_mysql.c | 6 ++---- 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 centrallix-lib/tests/test_xstring_00.c diff --git a/centrallix-lib/src/xstring.c b/centrallix-lib/src/xstring.c index 4697d86be..cd112f0c4 100644 --- a/centrallix-lib/src/xstring.c +++ b/centrallix-lib/src/xstring.c @@ -671,7 +671,9 @@ xsSubst(pXString this, int offset, int len, char* rep, int replen) ASSERTMAGIC(this, MGK_XSTRING); CXSEC_VERIFY(*this); - + + int i; + /** Figure some default lengths **/ if (offset > this->Length || offset < 0) { @@ -680,9 +682,18 @@ xsSubst(pXString this, int offset, int len, char* rep, int replen) } if (len == -1) len = strlen(this->String + offset); if (replen == -1) replen = strlen(rep); - + /** Make sure we have enough room **/ if (len < replen) xsCheckAlloc(this, replen - len); + + /** Make sure we do not end up with a partial UTF-8 character **/ + for (i = 0; i < 4; i++) + { + if((this->String[offset + replen + i] & 0xC0) != 0x80) + break; + } + len += i; + /** Move the tail of the string, and plop the replacement in there **/ memmove(this->String+offset+replen, this->String+offset+len, this->Length + 1 - (offset+len)); diff --git a/centrallix-lib/tests/test_xstring_00.c b/centrallix-lib/tests/test_xstring_00.c new file mode 100644 index 000000000..7da3c8436 --- /dev/null +++ b/centrallix-lib/tests/test_xstring_00.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include "../../centrallix/include/charsets.h" + +long long +test(char** tname) + { + int i; + int iter; + size_t len; + + char* str2 = "Χαίρετε"; + len = chrCharLength(str2); + printf("num chars = %d", len); + assert(len == 7); + + *tname = "Accessing centrallix"; + iter = 10000000; + for(i=0;iString); - // i = mblen(where_clause->String, strlen(where_clause->String)); - xsConcatenate(where_clause, " (", -1); + i = strlen(where_clause->String); + xsConcatenate(where_clause, " (", -1); mysd_internal_TreeToClause(subtree, tdata, where_clause,conn); if (subtree->DataType == DATA_T_STRING) { From 1ff8024845dabc92d3fed81e1e7813fc71941948 Mon Sep 17 00:00:00 2001 From: Tommy O'Brien <38384082+ttobrien@users.noreply.github.com> Date: Fri, 10 Jul 2020 15:38:15 -0600 Subject: [PATCH 039/124] Move charsets.c to centrallix-lib --- centrallix-lib/src/charsets.c | 638 ++++++++++++++++++++++++++++++++++ 1 file changed, 638 insertions(+) create mode 100644 centrallix-lib/src/charsets.c diff --git a/centrallix-lib/src/charsets.c b/centrallix-lib/src/charsets.c new file mode 100644 index 000000000..bf1ee2726 --- /dev/null +++ b/centrallix-lib/src/charsets.c @@ -0,0 +1,638 @@ +#include "charsets.h" +#include "centrallix.h" +#include +#include +#include +#include +#include + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2001 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: charsets.c, charsets.h */ +/* Author: Daniel Rothfus */ +/* Creation: June 29, 2011 */ +/* Description: This module provides utilities for working with the */ +/* variable character set support built into Centrallix. */ +/************************************************************************/ + +char* chrGetEquivalentName(char* name) + { + pStructInf highestCharsetNode; + char * charsetValue; + + // Try to find the requested attribute + highestCharsetNode = stLookup(CxGlobals.CharsetMap, name); + if(highestCharsetNode) + { + stAttrValue(highestCharsetNode, NULL, &charsetValue, 0); + return charsetValue; + } + else + { + // If not, return the system's name for the charset. + return nl_langinfo(CODESET); + } + } + +/** String Functions Follow **/ +size_t chrGetCharNumber(char* character) + { + size_t bytesParsed; + wchar_t firstChar = 0; + if(!character) + return CHR_INVALID_ARGUMENT; + bytesParsed = mbrtowc(&firstChar, character, strlen(character), NULL); + if(bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) + { + return CHR_INVALID_CHAR; + } + else + { + return (size_t)firstChar; + } + } + +char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* bufferLength) + { + size_t strCharLen, strByteLen, charsScanned = 0, bytesScanned = 0, tmpBytesScanned, bytesInStringScanned = 0; + char* initialPos, *output; + mbstate_t state; + + /** Initialize the multi-byte scanning state **/ + memset(&state, 0, sizeof(state)); + + strByteLen = strlen(string); + strCharLen = mbstowcs(NULL, string, 0); + if(strCharLen == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Bounds checking **/ + if(end > strCharLen) + end = strCharLen; + if(begin > end) + begin = end; + + /** Check if this is to return the entire string. **/ + if(begin == 0 && end == strCharLen){ + *bufferLength = 0; + return string; + } + + /** Check if this is being used as a shortcut for right **/ + if(end == strCharLen){ + return chrRight(string, strCharLen - begin, bufferLength); + } + + /** Find the required number of bytes for the output buffer **/ + /** Scan to the beginning character **/ + while(charsScanned < begin) + { + tmpBytesScanned = mbrtowc(NULL, string + bytesScanned, strByteLen - bytesScanned, &state); + if(tmpBytesScanned == (size_t)-1 || tmpBytesScanned == (size_t)-2) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + bytesScanned += tmpBytesScanned; + charsScanned++; + } + initialPos = string + bytesScanned; + + /** Find ending position **/ + while(charsScanned < end) + { + tmpBytesScanned = mbrtowc(NULL, string + bytesScanned, strByteLen - bytesScanned, &state); + if(tmpBytesScanned == (size_t)-1 || tmpBytesScanned == (size_t)-2) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + bytesScanned += tmpBytesScanned; + bytesInStringScanned += tmpBytesScanned; + charsScanned++; + } + + /** Now chars scanned is the size of the buffer to use **/ + if(buffer && (bytesInStringScanned < *bufferLength)) + { + *bufferLength = 0; + output = buffer; + } + else + { + output = (char *)nmSysMalloc(bytesInStringScanned + 1); + if(!output) + { + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = bytesInStringScanned + 1; + } + + /** Convert the string at initial pos using only so many characters **/ + strncpy(output, initialPos, bytesInStringScanned); + + /** Append null and return **/ + output[bytesInStringScanned] = '\0'; + return output; + } + +size_t chrSubstringIndex(char* string, char* character) + { + char * ptr; + size_t tmpLen1, tmpLen2; + if(!string || !character) + return CHR_INVALID_ARGUMENT; + ptr = strstr(string, character); + if (ptr == NULL) + { + return CHR_NOT_FOUND; + } + else + { + tmpLen1 = mbstowcs(NULL, string, 0); + tmpLen2 = mbstowcs(NULL, ptr, 0); + if(tmpLen1 == (size_t)-1 || tmpLen2 == (size_t)-1) + return CHR_INVALID_CHAR; + else + { + return tmpLen1 - tmpLen2; + } + } + } + +char* chrToUpper(char* string, char* buffer, size_t* bufferLength) + { + size_t stringCharLength, currentPos, newStrByteLength; + char* toReturn; + wchar_t* longBuffer; + + /** Check arguments **/ + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + stringCharLength = mbstowcs(NULL, string, 0); + if(stringCharLength == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Create wchar_t buffer */ + longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); + if(!longBuffer){ + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + mbstowcs(longBuffer, string, stringCharLength + 1); + currentPos = stringCharLength; + while(currentPos--) + longBuffer[currentPos] = towupper(longBuffer[currentPos]); + + newStrByteLength = wcstombs(NULL, longBuffer, 0); + if(newStrByteLength == (size_t)-1) + { + nmSysFree(longBuffer); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + if(buffer && (newStrByteLength < *bufferLength)) + { + toReturn = buffer; + *bufferLength = 0; + } + else + { + toReturn = (char *)nmSysMalloc(newStrByteLength + 1); + if(!toReturn) + { + nmSysFree(longBuffer); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = newStrByteLength + 1; + } + + /** Copy over to output buffer **/ + wcstombs(toReturn, longBuffer, newStrByteLength + 1); + nmSysFree(longBuffer); + return toReturn; + } + +char* chrToLower(char* string, char* buffer, size_t* bufferLength) + { + size_t stringCharLength, currentPos, newStrByteLength; + char* toReturn; + wchar_t* longBuffer; + + /** Check arguments **/ + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + stringCharLength = mbstowcs(NULL, string, 0); + if(stringCharLength == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Create wchar_t buffer */ + longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); + if(!longBuffer){ + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + mbstowcs(longBuffer, string, stringCharLength + 1); + currentPos = stringCharLength; + while(currentPos--) + longBuffer[currentPos] = towlower(longBuffer[currentPos]); + + newStrByteLength = wcstombs(NULL, longBuffer, 0); + if(newStrByteLength == (size_t)-1) + { + nmSysFree(longBuffer); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + if(buffer && (newStrByteLength < *bufferLength)) + { + toReturn = buffer; + *bufferLength = 0; + } + else + { + toReturn = (char *)nmSysMalloc(newStrByteLength + 1); + if(!toReturn) + { + nmSysFree(longBuffer); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = newStrByteLength + 1; + } + + /** Copy over to output buffer **/ + wcstombs(toReturn, longBuffer, newStrByteLength + 1); + nmSysFree(longBuffer); + return toReturn; + } + +size_t chrCharLength(char* string) + { + size_t length; + if(!string) + return CHR_INVALID_ARGUMENT; + length = mbstowcs(NULL, string, 0); + if(length == (size_t)-1) + return CHR_INVALID_CHAR; + else + return length; + } + +char* chrNoOverlong(char* string) + { + //printf("No Overlong\nInit String: %s\n", string); + size_t stringCharLength, newStrByteLength; + char* toReturn; + wchar_t* longBuffer; + + /** Check arguments **/ + if(!string) + return CHR_INVALID_ARGUMENT; + + stringCharLength = mbstowcs(NULL, string, 0); + if(stringCharLength == (size_t)-1) + { + return NULL; + } + //printf("Args checked\n"); + /** Create wchar_t buffer */ + longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); + if(!longBuffer) + return NULL; + mbstowcs(longBuffer, string, stringCharLength + 1); + //printf("Made wide buffer\n"); + //wprintf(L"Wide String: %ls\n, longBuffer"); + /** Convert back to MBS **/ + newStrByteLength = wcstombs(NULL, longBuffer, 0); + if(newStrByteLength == (size_t)-1) + { + nmSysFree(longBuffer); + return NULL; + } + //printf("got size\n"); + toReturn = (char *)nmSysMalloc(newStrByteLength + 1); + if(!toReturn) + { + nmSysFree(longBuffer); + return NULL; + } + + wcstombs(toReturn, longBuffer, newStrByteLength + 1); + //printf("String: %s\n", toReturn); + nmSysFree(longBuffer); + //printf("Done\n"); + //nmSysFree(string); //good? + return toReturn; + } + +char* chrRight(char* string, size_t offsetFromEnd, size_t* returnCode) + { + size_t currentPos = 0, numScanned = 0; + size_t strByteLen, strCharLen, step = 0; + mbstate_t currentState; + + /** Clear initial state **/ + memset(¤tState, 0, sizeof(currentState)); + + strByteLen = strlen(string); + strCharLen = mbstowcs(NULL, string, 0); + if(strCharLen == (size_t)-1) + { + *returnCode = CHR_INVALID_CHAR; + return NULL; + } + + /** Boundary checking **/ + if (offsetFromEnd > strCharLen) + offsetFromEnd = strCharLen; + if (offsetFromEnd < 0) + offsetFromEnd = 0; + + /** Scan through until we hit the offset into the string that we need to. **/ + while(numScanned < (strCharLen - offsetFromEnd)) + { + step = mbrtowc(NULL, string + currentPos, strByteLen + 1, ¤tState); + if(step == (size_t)-1 || step == (size_t)-2) + { + *returnCode = CHR_INVALID_CHAR; + return NULL; + } + if(step == 0) /* Hit the end of the string unintentionally */ + break; + numScanned++; + currentPos += step; + } + + /** All done - return offset into original string **/ + *returnCode = 0; + return string + currentPos; + } + +char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* bufferLength) + { + wchar_t current, *escBuf, *badBuf; + mbstate_t state; + char * output; + size_t escCharLen, badCharLen, numEscapees = 0, i, j, readPos, insertPos, strByteLen, charLen; + + /** Check parameters **/ + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + /** The esc and bad parameters in wchar_t form **/ + strByteLen = strlen(string); + escCharLen = mbstowcs(NULL, escape, 0); + badCharLen = mbstowcs(NULL, bad, 0); + if (escCharLen == (size_t)-1 || badCharLen == (size_t)-1) + { + /** This is checked below, but we check here for clarity + ** as well as to have the check before we pass the values + ** to nmSysMalloc(). + **/ + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Declare buffer variables here! **/ + escBuf = nmSysMalloc(sizeof(wchar_t) * (escCharLen + 2)); + if(!escBuf) + { + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + badBuf = nmSysMalloc(sizeof(wchar_t) * (badCharLen + 1)); + if(!badBuf) + { + nmSysFree(escBuf); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + + escCharLen = mbstowcs(escBuf, escape, escCharLen + 1); /* Translate over the escape characters */ + if(escCharLen == (size_t)-1) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + escBuf[escCharLen] = '\\'; /* Add in the / character to those to escape. */ + escBuf[++escCharLen] = '\0'; + + badCharLen = mbstowcs(badBuf, bad, badCharLen + 1); /* Translate over the bad characters */ + if(badCharLen == (size_t)-1) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + + /** Clear the current state of the UTF-8 state holder **/ + memset(&state, '\0', sizeof(state)); + + /** Scan through the string **/ + for(i = 0; string[i] != '\0';) + { + charLen = mbrtowc(¤t, string + i, strByteLen - i, &state); + if(charLen == (size_t)-1 || charLen == (size_t)-2) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + i += charLen; + + for(j = 0; j < badCharLen; j++) + { + if(current == badBuf[j]) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_BAD_CHAR; + return NULL; + } + } + for(j = 0; j < escCharLen; j++) + { + if(current == escBuf[j]) + { + numEscapees++; + break; + } + } + } + if(numEscapees == 0) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = 0; + return string; + } + + /** Reinitialize state **/ + memset(&state, '\0', sizeof(state)); + + /** Find the buffer to put the results into **/ + if(buffer && (numEscapees + strByteLen < *bufferLength)) + { + output = buffer; + *bufferLength = 0; + } + else + { + output = nmSysMalloc(numEscapees + strByteLen + 1); + if(!output) + { + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = numEscapees + strByteLen + 1; + } + + /** Insert back slashes **/ + for(readPos = 0, insertPos = 0; readPos < strByteLen;) + { + charLen = mbrtowc(¤t, string + readPos, strByteLen - readPos, &state); + if (charLen == (size_t)-1 || charLen == (size_t)-2) + { + /** For clarity **/ + nmSysFree(escBuf); + nmSysFree(badBuf); + *bufferLength = CHR_BAD_CHAR; + return NULL; + } + for(j = 0; j < escCharLen; j++) + { + if(current == escBuf[j]) + { + output[insertPos] = '\\'; + insertPos++; + break; + } + } + while(charLen--) + { + output[insertPos++] = string[readPos++]; + } + } + output[numEscapees + strByteLen] = '\0'; /* Cap off with NULL character */ + nmSysFree(escBuf); + nmSysFree(badBuf); + return output; + } + +char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength) + { + size_t stringCharLen, newStrByteLen, c, stringByteLength; + long long numSpaces; + char * toReturn; + + if(!string || !bufferLength) + { + *bufferLength = CHR_INVALID_ARGUMENT; + return NULL; + } + + /** Calculate the number of spaces to add **/ + stringByteLength = strlen(string); + stringCharLen = mbstowcs(NULL, string, 0); + if(stringCharLen == (size_t)-1) + { + *bufferLength = CHR_INVALID_CHAR; + return NULL; + } + numSpaces = (long long)minLength - stringCharLen; + if(numSpaces <= 0) /* If we do not have to add spaces, return the original string. */ + { + *bufferLength = 0; + return string; + } + + newStrByteLen = numSpaces + stringByteLength; /* The needed number of bytes in the new string */ + + /** Set the string to return. **/ + if(buffer && (newStrByteLen < *bufferLength)) + { + toReturn = buffer; + *bufferLength = 0; + } + else + { + toReturn = nmSysMalloc(newStrByteLen + 1); + if(!toReturn) + { + *bufferLength = CHR_MEMORY_OUT; + return NULL; + } + *bufferLength = newStrByteLen + 1; + } + + c = numSpaces; + while(c--) + { + toReturn[c] = ' '; + } + c = newStrByteLen; + while(c-- > numSpaces) + { + toReturn[c] = string[c - numSpaces]; + } + toReturn[newStrByteLen] = '\0'; + return toReturn; + } + +int chrValid(int result) + { + return !(result == CHR_MEMORY_OUT || result == CHR_BAD_CHAR || result == CHR_INVALID_CHAR || result == CHR_INVALID_ARGUMENT || result == CHR_NOT_FOUND); + } From 3b30f3aa06da2f0b49d3e44e92a44c70297d1fe2 Mon Sep 17 00:00:00 2001 From: Tommy O'Brien <38384082+ttobrien@users.noreply.github.com> Date: Fri, 10 Jul 2020 15:39:59 -0600 Subject: [PATCH 040/124] Move charsets.h to centrallix-lib --- centrallix-lib/include/charsets.h | 224 ++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 centrallix-lib/include/charsets.h diff --git a/centrallix-lib/include/charsets.h b/centrallix-lib/include/charsets.h new file mode 100644 index 000000000..5a1e3319e --- /dev/null +++ b/centrallix-lib/include/charsets.h @@ -0,0 +1,224 @@ +#ifndef _CHARSETS_H +#define _CHARSETS_H + +#include + +/************************************************************************/ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2001 LightSys Technology Services, Inc. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ +/* A copy of the GNU General Public License has been included in this */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: charsets.c, charsets.h */ +/* Author: Daniel Rothfus */ +/* Creation: June 29, 2011 */ +/* Description: This module provides utilities for working with the */ +/* variable character set support built into Centrallix. */ +/************************************************************************/ + +/** \defgroup charset Character Set Utilities + \brief This module provides utilities for handling the different character + set support implemented in Centrallix. + /{ */ + +/** \defgroup charset_lookups Looking Up Equivalent Character Set Names + \brief This contains a collection of macros that define string constants that + are to be valid lookup keys in charsetmap.cfg and a function to look up their + equivalent values. + \{ */ + +/** \brief The string constant for the HTTP generation module. */ +#define CHR_MODULE_HTTP "http" +/** \brief The string constant for the MySQL database driver. */ +#define CHR_MODULE_MYSQL "mysql" +/** \brief A string constant for the Sybase database driver. */ +#define CHR_MODULE_SYBASE "sybase" + +/** \brief This is the key in centrallix.conf that specifies the charsetmap.cfg + file */ +#define CHR_CHARSETMAP_FILE_KEY "charsetmap_file" + +/** \brief Check for an equivalent name for the current character set. + + (See charsetmap.cfg for an introduction to equivalent names.) + \param name The name of the module/subsystem/library that needs a name for the + current character set. + \return This returns a pointer to the name of the charset. This should never + return NULL, though it may return an incorrect string if the application is + configured incorrectly. */ +char* chrGetEquivalentName(char* name); + +/** \} + \defgroup charset_stringfuncs String Functions + \brief These functions operate on multibyte-character strings. (Or single + byte, but they are not as efficient as possible with those.) + + This is a brief note for the calling convention of all of these functions: + If a function returns a size_t, it will either return a valid result or one of + the CHR_* macros on failure. + If a function takes the arguments buffer and bufferLength, these functions will + return a pointer to the resulting character string. The return of these + functions will either be a valid character string or NULL on error. If there + was an error, the bufferLength will be set to the corresponding CHR_* macro + describing the error/problem. If a non-NULL value was returned, the origin of + the buffer can be found by examining the pointer returned and the bufferLength + value after the function is done. If the bufferLength is 0 and the pointer + returned is equal to buffer, the given preallocated buffer was used for the + results. If the bufferLength is 0 and the returned pointer is not buffer, then + the pointer points to some place in the original string, which is only done in + certain circumstances. Otherwise, if the bufferSize is non-zero, the function + had to allocate memory on the heap with nmSysMalloc, so the returned string + will need to be freed. + \todo Make a these functions all work with single byte encodings quickly as + as well? (Add special cases for single byte strings?) + \{ */ + +/** \brief This constant is returned when an invalid UTF-8 character is found + for functions that return type size_t. + + This will also be returned if there was a character set conversion error. */ +#define CHR_INVALID_CHAR (size_t)-2 +/** \brief This constant is returned for searching functions when the desired + character is not found in the chr module. */ +#define CHR_NOT_FOUND (size_t)-1 +/** \brief This is returned when an invalid argument is passed to a function in + the chr module. + + This is used for such things as NULL pointers with required arguments. */ +#define CHR_INVALID_ARGUMENT (size_t)-3 +/** \brief Returned when there is not enough memory to do an operation. */ +#define CHR_MEMORY_OUT (size_t)-4 +/** \brief This is passed when a disallowed (not invalid) character is found + in a string. */ +#define CHR_BAD_CHAR (size_t)-5 + +/** \brief Get the numeric value of a character (possibly multi-byte). + \param character A pointer to the character to analyze. + \return This returns the numeric value of the first character in the string in + character based on the current locale. This could also return an error, such + as CHR_NOT_FOUND or CHR_INVALID_CHAR. (See the extended module description for + more information.) */ +size_t chrGetCharNumber(char* character); + +/** \brief Get a substring of a given string. + \param string The (possibly multibyte) string to find the substring in. + \param begin The character index of the first CHARACTER to start copying at. + \param end The character index of the character (not byte) right after the + substring to find. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the substring or NULL on error. (See the extended + module description for more information.) */ +char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* bufferLength); + +/** \brief Find the first instance of a substring in string. + \param string The string to find the substring in. + \param substring The substring to find in the string. + \return Thist returns the offset into the string that the character was found + at or an error, such as CHR_NOT_FOUND or CHR_INVALID_CHAR. (See the extended + module description for more information.) */ +size_t chrSubstringIndex(char* string, char* substring); + +/** \brief Convert a (possibly multibyte) string to upper case. + \param string The string to convert to upper case. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the upper case string or NULL on error. (See the extended + module description for more information.) */ +char* chrToUpper(char* string, char* buffer, size_t* bufferLength); + +/** \brief Convert a (possibly multibyte) string to lower case. + \param string The string to convert to lower case. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the lower case string or NULL on error. (See the extended + module description for more information.) */ +char* chrToLower(char* string, char* buffer, size_t* bufferLength); + +/** \brief This function returns the number of characters (NOT BYTES) in a + given string. + \param string The string to return the number of characters in. + \return This returns the length or an error such (but not limited to) as + CHR_INVALID_CHAR on error. */ +size_t chrCharLength(char* string); + +/** \brief This function ensures that a multibyte string will be in simplest form. + \param string The string to simplify. + \return This returns the same string but with the minimum amount of bytes used + or NULL on error. */ +char* chrNoOverlong(char* string); + +/** \brief Get a specific number of the rightmost characters in the string. + + This function always returns an offset into the original string since no + copying is ever needed. + \param string The string to get numChars number of rightmost characters. + \param numChars The number of characters to grab off of the right of the + string. + \param returnCode This takes the role of bufferLength in the other char* + returning functions for return codes. + \return This returns a pointer to the position in the original string where + only the numChar(th) right characters are viewable from. + */ +char* chrRight(char* string, size_t numChars, size_t* returnCode); + +/** \brief Escape certain characters in a string with '\' while banning some. + \param string The string to escape. + \param escape A string with all of the characters to escape. + \param bad The bad characters to stop processing on. When it stops processing, + it returns NULL and sets the value of bufferLength to CHR_BAD_CHAR. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the escaped string which may point to the preallocated + buffer or an allocated buffer or NULL if a bad character was encountered. (See + the extended module description for more information.) */ +char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* bufferLength); + +/** \brief Create a string of a certain minimum size with spaces padding the + string to the right if the string is not long enough. + \param string The string to resize to the minimum given length. + \param minLength The minimum number of characters that you want the string to + take up. + \param buffer A preallocated buffer that you want this function to use or NULL. + \param bufferLength The length of the preallocated buffer. This must never + be NULL even if buffer is! + \return This returns the buffered string or NULL on error. Please note that + this is extremely prone to returning the original string because this is done + whenever the string is the same length or longer than the minLength. (See the + extended module description for more information.) + */ +char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength); + +/** \brief Convenience function for checking the validity of results. + \param result The result value obtained from the string function. + \return Returns 1 if valid, 0 if not valid. + */ +int chrValid(int result); + +/** \} */ + +/** \} */ + +#endif From c6fb2809ec8c8f88414e9afbec78a9cff32de70e Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Fri, 10 Jul 2020 17:16:07 -0600 Subject: [PATCH 041/124] Undidrefactoring and added chrCharLength to xstring module --- centrallix-lib/include/charsets.h | 224 ----------- centrallix-lib/include/xstring.h | 5 +- centrallix-lib/src/charsets.c | 638 ------------------------------ centrallix-lib/src/xstring.c | 11 + 4 files changed, 15 insertions(+), 863 deletions(-) delete mode 100644 centrallix-lib/include/charsets.h delete mode 100644 centrallix-lib/src/charsets.c diff --git a/centrallix-lib/include/charsets.h b/centrallix-lib/include/charsets.h deleted file mode 100644 index 5a1e3319e..000000000 --- a/centrallix-lib/include/charsets.h +++ /dev/null @@ -1,224 +0,0 @@ -#ifndef _CHARSETS_H -#define _CHARSETS_H - -#include - -/************************************************************************/ -/* Centrallix Application Server System */ -/* Centrallix Core */ -/* */ -/* Copyright (C) 1998-2001 LightSys Technology Services, Inc. */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ -/* 02111-1307 USA */ -/* */ -/* A copy of the GNU General Public License has been included in this */ -/* distribution in the file "COPYING". */ -/* */ -/* Module: charsets.c, charsets.h */ -/* Author: Daniel Rothfus */ -/* Creation: June 29, 2011 */ -/* Description: This module provides utilities for working with the */ -/* variable character set support built into Centrallix. */ -/************************************************************************/ - -/** \defgroup charset Character Set Utilities - \brief This module provides utilities for handling the different character - set support implemented in Centrallix. - /{ */ - -/** \defgroup charset_lookups Looking Up Equivalent Character Set Names - \brief This contains a collection of macros that define string constants that - are to be valid lookup keys in charsetmap.cfg and a function to look up their - equivalent values. - \{ */ - -/** \brief The string constant for the HTTP generation module. */ -#define CHR_MODULE_HTTP "http" -/** \brief The string constant for the MySQL database driver. */ -#define CHR_MODULE_MYSQL "mysql" -/** \brief A string constant for the Sybase database driver. */ -#define CHR_MODULE_SYBASE "sybase" - -/** \brief This is the key in centrallix.conf that specifies the charsetmap.cfg - file */ -#define CHR_CHARSETMAP_FILE_KEY "charsetmap_file" - -/** \brief Check for an equivalent name for the current character set. - - (See charsetmap.cfg for an introduction to equivalent names.) - \param name The name of the module/subsystem/library that needs a name for the - current character set. - \return This returns a pointer to the name of the charset. This should never - return NULL, though it may return an incorrect string if the application is - configured incorrectly. */ -char* chrGetEquivalentName(char* name); - -/** \} - \defgroup charset_stringfuncs String Functions - \brief These functions operate on multibyte-character strings. (Or single - byte, but they are not as efficient as possible with those.) - - This is a brief note for the calling convention of all of these functions: - If a function returns a size_t, it will either return a valid result or one of - the CHR_* macros on failure. - If a function takes the arguments buffer and bufferLength, these functions will - return a pointer to the resulting character string. The return of these - functions will either be a valid character string or NULL on error. If there - was an error, the bufferLength will be set to the corresponding CHR_* macro - describing the error/problem. If a non-NULL value was returned, the origin of - the buffer can be found by examining the pointer returned and the bufferLength - value after the function is done. If the bufferLength is 0 and the pointer - returned is equal to buffer, the given preallocated buffer was used for the - results. If the bufferLength is 0 and the returned pointer is not buffer, then - the pointer points to some place in the original string, which is only done in - certain circumstances. Otherwise, if the bufferSize is non-zero, the function - had to allocate memory on the heap with nmSysMalloc, so the returned string - will need to be freed. - \todo Make a these functions all work with single byte encodings quickly as - as well? (Add special cases for single byte strings?) - \{ */ - -/** \brief This constant is returned when an invalid UTF-8 character is found - for functions that return type size_t. - - This will also be returned if there was a character set conversion error. */ -#define CHR_INVALID_CHAR (size_t)-2 -/** \brief This constant is returned for searching functions when the desired - character is not found in the chr module. */ -#define CHR_NOT_FOUND (size_t)-1 -/** \brief This is returned when an invalid argument is passed to a function in - the chr module. - - This is used for such things as NULL pointers with required arguments. */ -#define CHR_INVALID_ARGUMENT (size_t)-3 -/** \brief Returned when there is not enough memory to do an operation. */ -#define CHR_MEMORY_OUT (size_t)-4 -/** \brief This is passed when a disallowed (not invalid) character is found - in a string. */ -#define CHR_BAD_CHAR (size_t)-5 - -/** \brief Get the numeric value of a character (possibly multi-byte). - \param character A pointer to the character to analyze. - \return This returns the numeric value of the first character in the string in - character based on the current locale. This could also return an error, such - as CHR_NOT_FOUND or CHR_INVALID_CHAR. (See the extended module description for - more information.) */ -size_t chrGetCharNumber(char* character); - -/** \brief Get a substring of a given string. - \param string The (possibly multibyte) string to find the substring in. - \param begin The character index of the first CHARACTER to start copying at. - \param end The character index of the character (not byte) right after the - substring to find. - \param buffer A preallocated buffer that you want this function to use or NULL. - \param bufferLength The length of the preallocated buffer. This must never - be NULL even if buffer is! - \return This returns the substring or NULL on error. (See the extended - module description for more information.) */ -char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* bufferLength); - -/** \brief Find the first instance of a substring in string. - \param string The string to find the substring in. - \param substring The substring to find in the string. - \return Thist returns the offset into the string that the character was found - at or an error, such as CHR_NOT_FOUND or CHR_INVALID_CHAR. (See the extended - module description for more information.) */ -size_t chrSubstringIndex(char* string, char* substring); - -/** \brief Convert a (possibly multibyte) string to upper case. - \param string The string to convert to upper case. - \param buffer A preallocated buffer that you want this function to use or NULL. - \param bufferLength The length of the preallocated buffer. This must never - be NULL even if buffer is! - \return This returns the upper case string or NULL on error. (See the extended - module description for more information.) */ -char* chrToUpper(char* string, char* buffer, size_t* bufferLength); - -/** \brief Convert a (possibly multibyte) string to lower case. - \param string The string to convert to lower case. - \param buffer A preallocated buffer that you want this function to use or NULL. - \param bufferLength The length of the preallocated buffer. This must never - be NULL even if buffer is! - \return This returns the lower case string or NULL on error. (See the extended - module description for more information.) */ -char* chrToLower(char* string, char* buffer, size_t* bufferLength); - -/** \brief This function returns the number of characters (NOT BYTES) in a - given string. - \param string The string to return the number of characters in. - \return This returns the length or an error such (but not limited to) as - CHR_INVALID_CHAR on error. */ -size_t chrCharLength(char* string); - -/** \brief This function ensures that a multibyte string will be in simplest form. - \param string The string to simplify. - \return This returns the same string but with the minimum amount of bytes used - or NULL on error. */ -char* chrNoOverlong(char* string); - -/** \brief Get a specific number of the rightmost characters in the string. - - This function always returns an offset into the original string since no - copying is ever needed. - \param string The string to get numChars number of rightmost characters. - \param numChars The number of characters to grab off of the right of the - string. - \param returnCode This takes the role of bufferLength in the other char* - returning functions for return codes. - \return This returns a pointer to the position in the original string where - only the numChar(th) right characters are viewable from. - */ -char* chrRight(char* string, size_t numChars, size_t* returnCode); - -/** \brief Escape certain characters in a string with '\' while banning some. - \param string The string to escape. - \param escape A string with all of the characters to escape. - \param bad The bad characters to stop processing on. When it stops processing, - it returns NULL and sets the value of bufferLength to CHR_BAD_CHAR. - \param buffer A preallocated buffer that you want this function to use or NULL. - \param bufferLength The length of the preallocated buffer. This must never - be NULL even if buffer is! - \return This returns the escaped string which may point to the preallocated - buffer or an allocated buffer or NULL if a bad character was encountered. (See - the extended module description for more information.) */ -char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* bufferLength); - -/** \brief Create a string of a certain minimum size with spaces padding the - string to the right if the string is not long enough. - \param string The string to resize to the minimum given length. - \param minLength The minimum number of characters that you want the string to - take up. - \param buffer A preallocated buffer that you want this function to use or NULL. - \param bufferLength The length of the preallocated buffer. This must never - be NULL even if buffer is! - \return This returns the buffered string or NULL on error. Please note that - this is extremely prone to returning the original string because this is done - whenever the string is the same length or longer than the minLength. (See the - extended module description for more information.) - */ -char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength); - -/** \brief Convenience function for checking the validity of results. - \param result The result value obtained from the string function. - \return Returns 1 if valid, 0 if not valid. - */ -int chrValid(int result); - -/** \} */ - -/** \} */ - -#endif diff --git a/centrallix-lib/include/xstring.h b/centrallix-lib/include/xstring.h index 683b0e05d..0f208a6c4 100644 --- a/centrallix-lib/include/xstring.h +++ b/centrallix-lib/include/xstring.h @@ -26,7 +26,7 @@ /* realloc'ing string data structure. */ /************************************************************************/ - +#include #include #define XS_BLK_SIZ 256 @@ -73,6 +73,9 @@ int xsConcatQPrintf(pXString this, char* fmt, ...); pXString xsNew(); void xsFree(pXString this); +/** Needed utiliy function **/ +size_t chrCharLength(char* string); + #define XS_U_SEEK 2 #endif /* _XSTRING_H */ diff --git a/centrallix-lib/src/charsets.c b/centrallix-lib/src/charsets.c deleted file mode 100644 index bf1ee2726..000000000 --- a/centrallix-lib/src/charsets.c +++ /dev/null @@ -1,638 +0,0 @@ -#include "charsets.h" -#include "centrallix.h" -#include -#include -#include -#include -#include - -/************************************************************************/ -/* Centrallix Application Server System */ -/* Centrallix Core */ -/* */ -/* Copyright (C) 1998-2001 LightSys Technology Services, Inc. */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ -/* 02111-1307 USA */ -/* */ -/* A copy of the GNU General Public License has been included in this */ -/* distribution in the file "COPYING". */ -/* */ -/* Module: charsets.c, charsets.h */ -/* Author: Daniel Rothfus */ -/* Creation: June 29, 2011 */ -/* Description: This module provides utilities for working with the */ -/* variable character set support built into Centrallix. */ -/************************************************************************/ - -char* chrGetEquivalentName(char* name) - { - pStructInf highestCharsetNode; - char * charsetValue; - - // Try to find the requested attribute - highestCharsetNode = stLookup(CxGlobals.CharsetMap, name); - if(highestCharsetNode) - { - stAttrValue(highestCharsetNode, NULL, &charsetValue, 0); - return charsetValue; - } - else - { - // If not, return the system's name for the charset. - return nl_langinfo(CODESET); - } - } - -/** String Functions Follow **/ -size_t chrGetCharNumber(char* character) - { - size_t bytesParsed; - wchar_t firstChar = 0; - if(!character) - return CHR_INVALID_ARGUMENT; - bytesParsed = mbrtowc(&firstChar, character, strlen(character), NULL); - if(bytesParsed == (size_t) - 1 || bytesParsed == (size_t) - 2) - { - return CHR_INVALID_CHAR; - } - else - { - return (size_t)firstChar; - } - } - -char* chrSubstring(char* string, size_t begin, size_t end, char* buffer, size_t* bufferLength) - { - size_t strCharLen, strByteLen, charsScanned = 0, bytesScanned = 0, tmpBytesScanned, bytesInStringScanned = 0; - char* initialPos, *output; - mbstate_t state; - - /** Initialize the multi-byte scanning state **/ - memset(&state, 0, sizeof(state)); - - strByteLen = strlen(string); - strCharLen = mbstowcs(NULL, string, 0); - if(strCharLen == (size_t)-1) - { - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - /** Bounds checking **/ - if(end > strCharLen) - end = strCharLen; - if(begin > end) - begin = end; - - /** Check if this is to return the entire string. **/ - if(begin == 0 && end == strCharLen){ - *bufferLength = 0; - return string; - } - - /** Check if this is being used as a shortcut for right **/ - if(end == strCharLen){ - return chrRight(string, strCharLen - begin, bufferLength); - } - - /** Find the required number of bytes for the output buffer **/ - /** Scan to the beginning character **/ - while(charsScanned < begin) - { - tmpBytesScanned = mbrtowc(NULL, string + bytesScanned, strByteLen - bytesScanned, &state); - if(tmpBytesScanned == (size_t)-1 || tmpBytesScanned == (size_t)-2) - { - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - bytesScanned += tmpBytesScanned; - charsScanned++; - } - initialPos = string + bytesScanned; - - /** Find ending position **/ - while(charsScanned < end) - { - tmpBytesScanned = mbrtowc(NULL, string + bytesScanned, strByteLen - bytesScanned, &state); - if(tmpBytesScanned == (size_t)-1 || tmpBytesScanned == (size_t)-2) - { - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - bytesScanned += tmpBytesScanned; - bytesInStringScanned += tmpBytesScanned; - charsScanned++; - } - - /** Now chars scanned is the size of the buffer to use **/ - if(buffer && (bytesInStringScanned < *bufferLength)) - { - *bufferLength = 0; - output = buffer; - } - else - { - output = (char *)nmSysMalloc(bytesInStringScanned + 1); - if(!output) - { - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - *bufferLength = bytesInStringScanned + 1; - } - - /** Convert the string at initial pos using only so many characters **/ - strncpy(output, initialPos, bytesInStringScanned); - - /** Append null and return **/ - output[bytesInStringScanned] = '\0'; - return output; - } - -size_t chrSubstringIndex(char* string, char* character) - { - char * ptr; - size_t tmpLen1, tmpLen2; - if(!string || !character) - return CHR_INVALID_ARGUMENT; - ptr = strstr(string, character); - if (ptr == NULL) - { - return CHR_NOT_FOUND; - } - else - { - tmpLen1 = mbstowcs(NULL, string, 0); - tmpLen2 = mbstowcs(NULL, ptr, 0); - if(tmpLen1 == (size_t)-1 || tmpLen2 == (size_t)-1) - return CHR_INVALID_CHAR; - else - { - return tmpLen1 - tmpLen2; - } - } - } - -char* chrToUpper(char* string, char* buffer, size_t* bufferLength) - { - size_t stringCharLength, currentPos, newStrByteLength; - char* toReturn; - wchar_t* longBuffer; - - /** Check arguments **/ - if(!string || !bufferLength) - { - *bufferLength = CHR_INVALID_ARGUMENT; - return NULL; - } - - stringCharLength = mbstowcs(NULL, string, 0); - if(stringCharLength == (size_t)-1) - { - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - /** Create wchar_t buffer */ - longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); - if(!longBuffer){ - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - mbstowcs(longBuffer, string, stringCharLength + 1); - currentPos = stringCharLength; - while(currentPos--) - longBuffer[currentPos] = towupper(longBuffer[currentPos]); - - newStrByteLength = wcstombs(NULL, longBuffer, 0); - if(newStrByteLength == (size_t)-1) - { - nmSysFree(longBuffer); - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - if(buffer && (newStrByteLength < *bufferLength)) - { - toReturn = buffer; - *bufferLength = 0; - } - else - { - toReturn = (char *)nmSysMalloc(newStrByteLength + 1); - if(!toReturn) - { - nmSysFree(longBuffer); - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - *bufferLength = newStrByteLength + 1; - } - - /** Copy over to output buffer **/ - wcstombs(toReturn, longBuffer, newStrByteLength + 1); - nmSysFree(longBuffer); - return toReturn; - } - -char* chrToLower(char* string, char* buffer, size_t* bufferLength) - { - size_t stringCharLength, currentPos, newStrByteLength; - char* toReturn; - wchar_t* longBuffer; - - /** Check arguments **/ - if(!string || !bufferLength) - { - *bufferLength = CHR_INVALID_ARGUMENT; - return NULL; - } - - stringCharLength = mbstowcs(NULL, string, 0); - if(stringCharLength == (size_t)-1) - { - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - /** Create wchar_t buffer */ - longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); - if(!longBuffer){ - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - mbstowcs(longBuffer, string, stringCharLength + 1); - currentPos = stringCharLength; - while(currentPos--) - longBuffer[currentPos] = towlower(longBuffer[currentPos]); - - newStrByteLength = wcstombs(NULL, longBuffer, 0); - if(newStrByteLength == (size_t)-1) - { - nmSysFree(longBuffer); - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - if(buffer && (newStrByteLength < *bufferLength)) - { - toReturn = buffer; - *bufferLength = 0; - } - else - { - toReturn = (char *)nmSysMalloc(newStrByteLength + 1); - if(!toReturn) - { - nmSysFree(longBuffer); - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - *bufferLength = newStrByteLength + 1; - } - - /** Copy over to output buffer **/ - wcstombs(toReturn, longBuffer, newStrByteLength + 1); - nmSysFree(longBuffer); - return toReturn; - } - -size_t chrCharLength(char* string) - { - size_t length; - if(!string) - return CHR_INVALID_ARGUMENT; - length = mbstowcs(NULL, string, 0); - if(length == (size_t)-1) - return CHR_INVALID_CHAR; - else - return length; - } - -char* chrNoOverlong(char* string) - { - //printf("No Overlong\nInit String: %s\n", string); - size_t stringCharLength, newStrByteLength; - char* toReturn; - wchar_t* longBuffer; - - /** Check arguments **/ - if(!string) - return CHR_INVALID_ARGUMENT; - - stringCharLength = mbstowcs(NULL, string, 0); - if(stringCharLength == (size_t)-1) - { - return NULL; - } - //printf("Args checked\n"); - /** Create wchar_t buffer */ - longBuffer = nmSysMalloc(sizeof(wchar_t) * (stringCharLength + 1)); - if(!longBuffer) - return NULL; - mbstowcs(longBuffer, string, stringCharLength + 1); - //printf("Made wide buffer\n"); - //wprintf(L"Wide String: %ls\n, longBuffer"); - /** Convert back to MBS **/ - newStrByteLength = wcstombs(NULL, longBuffer, 0); - if(newStrByteLength == (size_t)-1) - { - nmSysFree(longBuffer); - return NULL; - } - //printf("got size\n"); - toReturn = (char *)nmSysMalloc(newStrByteLength + 1); - if(!toReturn) - { - nmSysFree(longBuffer); - return NULL; - } - - wcstombs(toReturn, longBuffer, newStrByteLength + 1); - //printf("String: %s\n", toReturn); - nmSysFree(longBuffer); - //printf("Done\n"); - //nmSysFree(string); //good? - return toReturn; - } - -char* chrRight(char* string, size_t offsetFromEnd, size_t* returnCode) - { - size_t currentPos = 0, numScanned = 0; - size_t strByteLen, strCharLen, step = 0; - mbstate_t currentState; - - /** Clear initial state **/ - memset(¤tState, 0, sizeof(currentState)); - - strByteLen = strlen(string); - strCharLen = mbstowcs(NULL, string, 0); - if(strCharLen == (size_t)-1) - { - *returnCode = CHR_INVALID_CHAR; - return NULL; - } - - /** Boundary checking **/ - if (offsetFromEnd > strCharLen) - offsetFromEnd = strCharLen; - if (offsetFromEnd < 0) - offsetFromEnd = 0; - - /** Scan through until we hit the offset into the string that we need to. **/ - while(numScanned < (strCharLen - offsetFromEnd)) - { - step = mbrtowc(NULL, string + currentPos, strByteLen + 1, ¤tState); - if(step == (size_t)-1 || step == (size_t)-2) - { - *returnCode = CHR_INVALID_CHAR; - return NULL; - } - if(step == 0) /* Hit the end of the string unintentionally */ - break; - numScanned++; - currentPos += step; - } - - /** All done - return offset into original string **/ - *returnCode = 0; - return string + currentPos; - } - -char* chrEscape(char* string, char* escape, char* bad, char* buffer, size_t* bufferLength) - { - wchar_t current, *escBuf, *badBuf; - mbstate_t state; - char * output; - size_t escCharLen, badCharLen, numEscapees = 0, i, j, readPos, insertPos, strByteLen, charLen; - - /** Check parameters **/ - if(!string || !bufferLength) - { - *bufferLength = CHR_INVALID_ARGUMENT; - return NULL; - } - - /** The esc and bad parameters in wchar_t form **/ - strByteLen = strlen(string); - escCharLen = mbstowcs(NULL, escape, 0); - badCharLen = mbstowcs(NULL, bad, 0); - if (escCharLen == (size_t)-1 || badCharLen == (size_t)-1) - { - /** This is checked below, but we check here for clarity - ** as well as to have the check before we pass the values - ** to nmSysMalloc(). - **/ - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - /** Declare buffer variables here! **/ - escBuf = nmSysMalloc(sizeof(wchar_t) * (escCharLen + 2)); - if(!escBuf) - { - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - badBuf = nmSysMalloc(sizeof(wchar_t) * (badCharLen + 1)); - if(!badBuf) - { - nmSysFree(escBuf); - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - - escCharLen = mbstowcs(escBuf, escape, escCharLen + 1); /* Translate over the escape characters */ - if(escCharLen == (size_t)-1) - { - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - escBuf[escCharLen] = '\\'; /* Add in the / character to those to escape. */ - escBuf[++escCharLen] = '\0'; - - badCharLen = mbstowcs(badBuf, bad, badCharLen + 1); /* Translate over the bad characters */ - if(badCharLen == (size_t)-1) - { - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - - /** Clear the current state of the UTF-8 state holder **/ - memset(&state, '\0', sizeof(state)); - - /** Scan through the string **/ - for(i = 0; string[i] != '\0';) - { - charLen = mbrtowc(¤t, string + i, strByteLen - i, &state); - if(charLen == (size_t)-1 || charLen == (size_t)-2) - { - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - i += charLen; - - for(j = 0; j < badCharLen; j++) - { - if(current == badBuf[j]) - { - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = CHR_BAD_CHAR; - return NULL; - } - } - for(j = 0; j < escCharLen; j++) - { - if(current == escBuf[j]) - { - numEscapees++; - break; - } - } - } - if(numEscapees == 0) - { - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = 0; - return string; - } - - /** Reinitialize state **/ - memset(&state, '\0', sizeof(state)); - - /** Find the buffer to put the results into **/ - if(buffer && (numEscapees + strByteLen < *bufferLength)) - { - output = buffer; - *bufferLength = 0; - } - else - { - output = nmSysMalloc(numEscapees + strByteLen + 1); - if(!output) - { - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - *bufferLength = numEscapees + strByteLen + 1; - } - - /** Insert back slashes **/ - for(readPos = 0, insertPos = 0; readPos < strByteLen;) - { - charLen = mbrtowc(¤t, string + readPos, strByteLen - readPos, &state); - if (charLen == (size_t)-1 || charLen == (size_t)-2) - { - /** For clarity **/ - nmSysFree(escBuf); - nmSysFree(badBuf); - *bufferLength = CHR_BAD_CHAR; - return NULL; - } - for(j = 0; j < escCharLen; j++) - { - if(current == escBuf[j]) - { - output[insertPos] = '\\'; - insertPos++; - break; - } - } - while(charLen--) - { - output[insertPos++] = string[readPos++]; - } - } - output[numEscapees + strByteLen] = '\0'; /* Cap off with NULL character */ - nmSysFree(escBuf); - nmSysFree(badBuf); - return output; - } - -char* chrRightAlign(char* string, size_t minLength, char* buffer, size_t* bufferLength) - { - size_t stringCharLen, newStrByteLen, c, stringByteLength; - long long numSpaces; - char * toReturn; - - if(!string || !bufferLength) - { - *bufferLength = CHR_INVALID_ARGUMENT; - return NULL; - } - - /** Calculate the number of spaces to add **/ - stringByteLength = strlen(string); - stringCharLen = mbstowcs(NULL, string, 0); - if(stringCharLen == (size_t)-1) - { - *bufferLength = CHR_INVALID_CHAR; - return NULL; - } - numSpaces = (long long)minLength - stringCharLen; - if(numSpaces <= 0) /* If we do not have to add spaces, return the original string. */ - { - *bufferLength = 0; - return string; - } - - newStrByteLen = numSpaces + stringByteLength; /* The needed number of bytes in the new string */ - - /** Set the string to return. **/ - if(buffer && (newStrByteLen < *bufferLength)) - { - toReturn = buffer; - *bufferLength = 0; - } - else - { - toReturn = nmSysMalloc(newStrByteLen + 1); - if(!toReturn) - { - *bufferLength = CHR_MEMORY_OUT; - return NULL; - } - *bufferLength = newStrByteLen + 1; - } - - c = numSpaces; - while(c--) - { - toReturn[c] = ' '; - } - c = newStrByteLen; - while(c-- > numSpaces) - { - toReturn[c] = string[c - numSpaces]; - } - toReturn[newStrByteLen] = '\0'; - return toReturn; - } - -int chrValid(int result) - { - return !(result == CHR_MEMORY_OUT || result == CHR_BAD_CHAR || result == CHR_INVALID_CHAR || result == CHR_INVALID_ARGUMENT || result == CHR_NOT_FOUND); - } diff --git a/centrallix-lib/src/xstring.c b/centrallix-lib/src/xstring.c index cd112f0c4..9b9f4e610 100644 --- a/centrallix-lib/src/xstring.c +++ b/centrallix-lib/src/xstring.c @@ -982,3 +982,14 @@ xsConcatQPrintf(pXString this, char* fmt, ...) return rval; } +/*** chrCharLength - get number of characters in string + *** returns -1 if string is NULL or mbstowcs fails + ***/ +size_t chrCharLength(char* string) + { + size_t length; + if(!string) + return -1; + length = mbstowcs(NULL, string, 0); + return length; + } From ec099435a32989dd608df7d64e12c74e73581ad9 Mon Sep 17 00:00:00 2001 From: Developer - Kardia Date: Sat, 11 Jul 2020 16:35:32 -0600 Subject: [PATCH 042/124] switched howto.htm to UTF-8 --- centrallix-lib/tests/test_xstring_00.c | 32 +++++++++++++++++--------- centrallix-website/howto.htm | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/centrallix-lib/tests/test_xstring_00.c b/centrallix-lib/tests/test_xstring_00.c index 7da3c8436..c3fbdb0c4 100644 --- a/centrallix-lib/tests/test_xstring_00.c +++ b/centrallix-lib/tests/test_xstring_00.c @@ -4,23 +4,33 @@ #include #include #include -#include "../../centrallix/include/charsets.h" +#include +#include "xstring.h" long long test(char** tname) { - int i; - int iter; - size_t len; + *tname = "Test chrCharLength Function"; + int i, iter, len; + setlocale(LC_ALL, "en_US.UTF-8"); + + iter = 100000; + for(i=0;i Centrallix Howto - +