#ifndef INCLUDE_UDT #include "udt.h" #endif extern II_STATUS (*Ingres_trace_function)(); extern II_LO_HANDLER *usc_lo_handler; #define MAX_HEX_STRING_LENGTH 19 /* 8 x 2 char + leading '+0x', '-0x' */ #define HEX2INT_DEFAULT_SIZE 4 /* ie. integer4 */ II_STATUS hex2int( II_SCB *scb, II_DATA_VALUE *hexString, II_DATA_VALUE *size, /* target integer size */ II_DATA_VALUE *rdv ) { /* Sundry Init. */ char input[ MAX_HEX_STRING_LENGTH + 1 ]; char *endptr, *str = input; char msg[256]; /* Used for error processing */ unsigned long val = 0; unsigned long long llval = 0; long long mySize = 0; long long maxInt8 = 9223372036854775807; long prefixLength = 0, isNegative = 0;; short trueLength = 0; /* Set the conversion target size */ switch (size->db_length) { case 1: mySize = *(unsigned char *)size->db_data; break; case 2: mySize = *(short *)size->db_data; break; case 4: mySize = *(long *)size->db_data; break; case 8: mySize = *(long long *)size->db_data; }; #ifdef xDEBUG sprintf(msg, "hex2int(): set target size %d\n", mySize); (*Ingres_trace_function)(II_TRACE_FE_MASK, strlen(msg), msg); #endif if (mySize != 1 && mySize != 2 && mySize != 4 && mySize != 8) { sprintf(msg, "hex2int(): Invalid size '%d' specified. It must be one of 1, 2, 4, 8", mySize ); us_error(scb, 0x200012, msg); return(II_ERROR); }; /* Need to extract the input string. ** Check if excesive length for the output size etc... */ trueLength = *(short *)hexString->db_data; if (trueLength > MAX_HEX_STRING_LENGTH) { sprintf(msg, "hex2int(): character string is too long for conversion."); us_error(scb, 0x200013, msg); return(II_ERROR); }; memcpy(input, (char *)(hexString->db_data + sizeof(short)), trueLength); input[trueLength]='\0'; #ifdef xDEBUG sprintf(msg, "hex2int(): Process input hexString '%s' for integer%d\n", str, mySize ); (*Ingres_trace_function)(II_TRACE_FE_MASK, strlen(msg), msg); #endif if (! strncmp(str, "-", 1)) isNegative = 1; if (! strncmp(str, "0x", 2) || ! strncmp(str, "0X", 2)) { prefixLength = 2; } else if (! strncmp(str, "+0x", 3) || ! strncmp(str, "+0X", 3) || ! strncmp(str, "-0x", 3) || ! strncmp(str, "-0X", 3)) { prefixLength = 3; }; /* Confirm target size and hexString length match */ if (trueLength > (mySize * 2) + prefixLength) { sprintf(msg, "hex2int(): character string is too long for conversion into integer%d.", mySize ); us_error(scb, 0x200014, msg); return(II_ERROR); }; /* Init output. */ rdv->db_prec = 0; /* Set output precision */ *(long *)(rdv->db_data) = 0; /* Set a no match default */ /* Do conversion using C standard utilities. ** The prefix is ignored to avoid any confusion about the meaning of -0x. */ errno = 0; if (mySize <= 4) { val = strtoul((char *)(str + prefixLength), &endptr, 16); } else { llval = strtoull((char *)(str + prefixLength), &endptr, 16); }; if (errno != 0) { switch (errno) { case EINVAL: us_error(scb, 0x200015, "hex2int(): no conversion performed"); break; case ERANGE: printf("Error: Numeric Overflow has occurred.\n"); us_error(scb, 0x200016, "hex2int(): Numeric Overflow has occurred."); break; default: sprintf(msg, "hex2int(): Unexpected error %d encountered.", errno); us_error(scb, 0x200017, msg); }; return (II_ERROR); }; /* sprintf call succeeded, but were all characters used? */ if (*endptr != '\0') { sprintf(msg, "hex2int(): Non hex character '%c' found in string.", *endptr ); us_error(scb, 0x200020, msg); return (II_ERROR); }; if (endptr == str) { us_error(scb, 0x200021, "hex2int(): No convertable characters in input string"); return (II_ERROR); }; /* Looks Good! ** Adjust for negative numbers. */ #ifdef xDEBUG sprintf(msg, "hex2int(): Looks OK. val = %ld, llval = %lld\n", val, llval); (*Ingres_trace_function)(II_TRACE_FE_MASK, strlen(msg), msg); #endif switch (mySize) { case 1: if (val >= 128) val = val - 256; if (isNegative) val = -1 * val; /* Allow for a weird '-0x' case */ memcpy(rdv->db_data, &val, mySize); break; case 2: if (val >= 32768) val = val - 65536; if (isNegative) val = -1 * val; /* Allow for a weird '-0x' case */ memcpy(rdv->db_data, &val, mySize); break; case 4: if (val >= 2147483648) val = val - 4294967296; if (isNegative) val = -1 * val; /* Allow for a weird '-0x' case */ memcpy(rdv->db_data, &val, mySize); break; case 8: if (llval > maxInt8) llval = llval - maxInt8 - maxInt8 - 2; if (isNegative) llval = -1 * llval; /* Allow for a weird '-0x' case */ memcpy(rdv->db_data, &llval, mySize); break; }; return (II_OK); }; /*hex2int()*/ /* hex2int_ls() ** This is the lenspec routine used by hex2int(). */ II_STATUS hex2int_ls( II_SCB *scb, II_DT_ID *opid, II_DATA_VALUE *hexString, /* hexString */ II_DATA_VALUE *size, /* target integer size */ II_DATA_VALUE *rdv ) { char msg [ 256 ]; long long mySize = 0; switch (size->db_length) { case 1: mySize = *(unsigned char *)size->db_data; break; case 2: mySize = *(short *)size->db_data; break; case 4: mySize = *(long *)size->db_data; break; case 8: mySize = *(long long *)size->db_data; break; default: /* This shold never occur, but I'll leave it in... */ mySize = HEX2INT_DEFAULT_SIZE; }; switch (mySize) { case 1: case 2: case 4: case 8: rdv->db_length = mySize; break; default: /* An error will be generated in the main routine. ** The lenspec can just set a default at this point. */ rdv->db_length = HEX2INT_DEFAULT_SIZE; }; #ifdef xDEBUG sprintf(msg, "hex2int_ls() Have Set Size %d\n", rdv->db_length); (*Ingres_trace_function)(II_TRACE_FE_MASK, strlen(msg), msg); #endif return (II_OK); }; /* hex2int_ls() */