📄 convert.c
字号:
/* * =========================================================================== * PRODUCTION $Log: convert.c,v $ * PRODUCTION Revision 1000.1 2003/11/17 22:20:23 gouriano * PRODUCTION PRODUCTION: UPGRADED [ORIGINAL] Dev-tree R1.2 * PRODUCTION * =========================================================================== *//* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998-1999 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <tds_config.h>#include "tdsutil.h"#include "tds.h"#include "tdsconvert.h"# include <time.h>#include <assert.h>#include <errno.h>#ifdef DMALLOC#include <dmalloc.h>#endif#include <string.h>#ifndef HAVE_ATOLLstatic long intatoll(const char *nptr){ return atol(nptr);}#endif#ifdef NCBI_FTDSextern const int g__numeric_bytes_per_prec[];extern char *tds_money_to_string(TDS_MONEY *money, char *s);#define TDS_VECTOR_SIZE(x) (sizeof(x)/sizeof(x[0]))#endifstatic char software_version[] = "$Id: convert.c,v 1000.1 2003/11/17 22:20:23 gouriano Exp $";static void *no_unused_var_warn[] = {software_version, no_unused_var_warn};typedef unsigned short utf16_t;static TDS_INT tds_convert_int1(int srctype, const TDS_CHAR *src, int desttype, CONV_RESULT *cr);static TDS_INT tds_convert_int2(int srctype, const TDS_CHAR *src, int desttype, CONV_RESULT *cr);static TDS_INT tds_convert_int4(int srctype, const TDS_CHAR *src, int desttype, CONV_RESULT *cr);static TDS_INT tds_convert_int8(int srctype, const TDS_CHAR *src, int desttype, CONV_RESULT *cr);static int string_to_datetime(const char *datestr, int desttype, CONV_RESULT *cr );#define test_alloc(x) {if ((x)==NULL) return TDS_CONVERT_NOMEM;}#define IS_TINYINT(x) ( 0 <= (x) && (x) <= 0xff )#define IS_SMALLINT(x) ( -32768 <= (x) && (x) <= 32767 )/* f77: I don't write -2147483648, some compiler seem to have some problem * with this constant although is a valid 32bit value */#define IS_INT(x) ( (-2147483647l-1l) <= (x) && (x) <= 2147483647l )/** * \defgroup convert Conversion *//** \addtogroup convert * \@{ *//** * convert a number in string to a TDSNUMERIC * @return sizeof(TDS_NUMERIC) on success, TDS_CONVERT_* failure code on failure */static int string_to_numeric(const char *instr, const char *pend, CONV_RESULT *cr);/** * convert a zero terminated string to NUMERIC * @return sizeof(TDS_NUMERIC) on success, TDS_CONVERT_* failure code on failure */static int stringz_to_numeric(const char *instr, CONV_RESULT *cr);/** * convert a number in string to TDS_INT * @return TDS_CONVERT_* failure code if failure */static TDS_INT string_to_int(const char *buf,const char *pend,TDS_INT* res);#define TDS_CONVERT_NOAVAIL -2/** * convert a number in string to TDS_INT8 * @return TDS_CONVERT_* failure code if failure */static TDS_INT string_to_int8(const char *buf,const char *pend,TDS_INT8* res);static int store_hour(char *, char *, struct tds_time *);static int store_time(char *, struct tds_time * );static int store_yymmdd_date(char *, struct tds_time *);static int store_monthname(char *, struct tds_time *);static int store_numeric_date(char *, struct tds_time *);static int store_mday(char *, struct tds_time *);static int store_year(int, struct tds_time *);/* static int days_this_year (int years); */static int is_timeformat(char *);static int is_numeric(char *);static int is_alphabetic(char *);static int is_ampm(char *);static int is_monthname(char *);static int is_numeric_dateformat(char *);#if 0static TDS_UINT utf16len(const utf16_t* s);static const char *tds_prtype(int token);#endif/** * Return type suitable for conversions (convert all nullable types to * fixed type) * @param srctype type to convert * @param colsize size of type * @result type for conversion */int tds_get_conversion_type(int srctype, int colsize){ switch(srctype) { case SYBINTN: switch(colsize) { case 8: return SYBINT8; case 4: return SYBINT4; case 2: return SYBINT2; case 1: return SYBINT1; } break; case SYBFLTN: switch(colsize) { case 8: return SYBFLT8; case 4: return SYBREAL; } break; case SYBDATETIMN: switch(colsize) { case 8: return SYBDATETIME; case 4: return SYBDATETIME4; } break; case SYBMONEYN: switch(colsize) { case 8: return SYBMONEY; case 4: return SYBMONEY4; } break; /* altough tds_conmvert handle SYBBITN other routine use this * function to retrieve not variant type */ case SYBBITN: return SYBBIT; break; } return srctype;}/** * Copy a terminated string to result and return len or TDS_CONVERT_NOMEM */static TDS_INT string_to_result(const char* s,CONV_RESULT* cr){int len = strlen(s); cr->c = (TDS_CHAR *) malloc(len + 1); test_alloc(cr->c); memcpy(cr->c, s, len + 1); return len;}/** * Copy binary data to to result and return len or TDS_CONVERT_NOMEM */static TDS_INTbinary_to_result(const void* data,size_t len,CONV_RESULT* cr){ cr->ib = (TDS_CHAR *) malloc(len); test_alloc(cr->ib); memcpy(cr->ib, data, len); return len;}/* TODO implement me *//*static TDS_INT tds_convert_ntext(int srctype,TDS_CHAR *src,TDS_UINT srclen, int desttype, CONV_RESULT *cr){ return TDS_CONVERT_NOAVAIL;}*/static TDS_INT tds_convert_binary(int srctype, const TDS_UCHAR *src, TDS_INT srclen, int desttype, CONV_RESULT *cr){int cplen;int s;char *c;char hex2[3]; switch(desttype) { case SYBCHAR: case SYBVARCHAR: case SYBTEXT: /* NOTE: Do not prepend 0x to string. * The libraries all expect a bare string, without a 0x prefix. * Applications such as isql and query analyzer provide the "0x" prefix. */ /* 2 * source length + 1 for terminator */ cr->c = (TDS_CHAR *) malloc((srclen * 2) + 1); test_alloc(cr->c); c = cr->c; for (s = 0; s < srclen; s++) { sprintf(hex2, "%02x", src[s]); *c++ = hex2[0]; *c++ = hex2[1]; } *c = '\0'; return (srclen * 2); break; case SYBIMAGE: case SYBBINARY: case SYBVARBINARY: return binary_to_result(src, srclen, cr); break; case SYBINT1: case SYBINT2: case SYBINT4: case SYBINT8: case SYBMONEY4: case SYBMONEY: case SYBREAL: case SYBFLT8: cplen = get_size_by_type(desttype); if (cplen <= srclen) return binary_to_result(src, cplen, cr); cr->ib = (TDS_CHAR *) malloc(cplen); test_alloc(cr->ib); memcpy(cr->ib, src, srclen); memset(cr->ib+srclen, 0, cplen-srclen); return cplen; break; /* conversions not allowed */ case SYBDATETIME4: case SYBDATETIME: case SYBDATETIMN: /* TODO should we do some test for these types or work as ints ?? */ case SYBDECIMAL: case SYBNUMERIC: case SYBBIT: case SYBBITN: default: return TDS_CONVERT_NOAVAIL; break; }#ifndef NCBI_FTDS return TDS_CONVERT_FAIL;#endif}static TDS_INT tds_convert_char(int srctype, const TDS_CHAR *src, TDS_UINT srclen, int desttype, CONV_RESULT *cr){int i, j;unsigned char hex1;TDS_INT8 mymoney;TDS_INT mymoney4;char mynumber[39];const char *ptr, *pend;int point_found, places;TDS_INT tds_i;TDS_INT8 tds_i8;TDS_INT rc; switch(desttype) { case SYBCHAR: case SYBVARCHAR: case SYBTEXT: cr->c = (TDS_CHAR *) malloc(srclen + 1); test_alloc(cr->c); memcpy(cr->c, src, srclen); cr->c[srclen] = 0; return srclen; break; case SYBBINARY: case SYBIMAGE: case SYBVARBINARY: /* skip leading "0x" or "0X" */ if (src[0] == '0' && ( src[1] == 'x' || src[1] == 'X' )) { src += 2; srclen -= 2; } /* ignore trailing blanks and nulls */ /* FIXME is good to ignore null ?? */ while( srclen > 0 && (src[srclen-1] == ' ' || src[srclen-1] == '\0') ) --srclen; /* a binary string output will be half the length of */ /* the string which represents it in hexadecimal */ /* if srclen if odd we must add a "0" before ... */ j = 0; /* number where to start converting */ if (srclen & 1) { ++srclen; j = 1; --src; } cr->ib = (TDS_CHAR *) malloc(srclen / 2); test_alloc(cr->ib);#if 0 /* hey, I know this looks a bit cruddy, */ /* and I'm sure it can all be done in one */ /* statement, so go on, make my day! */ for ( i = 0, j = 0; i < srclen; i++, j++ ) { inp = src[i]; if ( inp > 47 && inp < 58 ) /* '0' thru '9' */ hex1 = inp - 48; else if ( inp > 96 && inp < 103 ) /* 'a' thru 'f' */ hex1 = inp - 87; else if ( inp > 64 && inp < 71 ) /* 'A' thru 'F' */ hex1 = inp - 55; else { fprintf(stderr,"error_handler: Attempt to convert data stopped by syntax error in source field \n"); return; } hex1 = hex1 << 4; i++; inp = src[i]; if ( inp > 47 && inp < 58 ) /* '0' thru '9' */ hex1 = hex1 | (inp - 48); else if ( inp > 96 && inp < 103 ) /* 'a' thru 'f' */ hex1 = hex1 | (inp - 87); else if ( inp > 64 && inp < 71 ) /* 'A' thru 'F' */ hex1 = hex1 | (inp - 55); else { fprintf(stderr,"error_handler: Attempt to convert data stopped by syntax error in source field \n"); return; } cr->ib[j] = hex1; }#else for ( i=srclen; --i >= j; ) { hex1 = src[i]; if( '0' <= hex1 && hex1 <= '9' ) hex1 &= 0x0f; else { hex1 &= 0x20 ^ 0xff; /* mask off 0x20 to ensure upper case */ if( 'A' <= hex1 && hex1 <= 'F' ) { hex1 -= ('A'-10); } else { tdsdump_log(TDS_DBG_INFO1,"error_handler: attempt to convert data stopped by syntax error in source field \n"); return TDS_CONVERT_SYNTAX; } } assert( hex1 < 0x10 ); if( i & 1 ) cr->ib[i/2] = hex1; else cr->ib[i/2] |= hex1 << 4; }#endif return srclen / 2; break; case SYBINT1: if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0) return rc; if (!IS_TINYINT(tds_i)) return TDS_CONVERT_OVERFLOW; cr->ti = tds_i; return sizeof(TDS_TINYINT); break; case SYBINT2: if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0) return rc; if (!IS_SMALLINT(tds_i)) return TDS_CONVERT_OVERFLOW; cr->si = tds_i; return sizeof(TDS_SMALLINT); break; case SYBINT4: if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0) return rc; cr->i = tds_i; return sizeof(TDS_INT); break; case SYBINT8: if ((rc = string_to_int8(src, src + srclen, &tds_i8)) < 0) return rc; cr->bi = tds_i8; return sizeof(TDS_INT8); break; case SYBFLT8: cr->f = atof(src); return sizeof(TDS_FLOAT); break; case SYBREAL: cr->r = atof(src); return sizeof(TDS_REAL); break; case SYBBIT: case SYBBITN: if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0) return TDS_CONVERT_OVERFLOW; cr->ti = tds_i ? 1 : 0; return sizeof(TDS_TINYINT); break; case SYBMONEY: case SYBMONEY4: /* TODO code similar to string_to_numeric... */ i = 0; places = 0; point_found = 0; pend = src + srclen; /* skip leading blanks */ for (ptr = src; ptr != pend && *ptr == ' '; ++ptr); switch ( ptr != pend ? *ptr : 0 ) { case '-': mynumber[i++] = '-'; /* fall through*/ case '+': ptr++; for (; ptr != pend && *ptr == ' '; ++ptr); break; } for(; ptr != pend; ptr++) /* deal with the rest */ { if (isdigit((unsigned char) *ptr) ) /* it's a number */ { /* no more than 4 decimal digits */ if (places < 4) mynumber[i++] = *ptr; /* assure not buffer overflow */ if (i==30) return TDS_CONVERT_OVERFLOW; if (point_found) { /* if we passed a decimal point */ /* count digits after that point */ ++places; } } else if (*ptr == '.') /* found a decimal point */ { if (point_found) /* already had one. error */ return TDS_CONVERT_SYNTAX; point_found = 1; } else /* first invalid character */ return TDS_CONVERT_SYNTAX; /* lose the rest. */ } for ( j = places; j < 4; j++ ) mynumber[i++] = '0'; mynumber[i] = 0; /* FIXME overflow not handled */ if (desttype == SYBMONEY) { mymoney = atoll(mynumber); memcpy(&(cr->m), &mymoney, sizeof(TDS_MONEY) ); return sizeof(TDS_MONEY); } else { mymoney4 = atol(mynumber); memcpy(&(cr->m4), &mymoney4, sizeof(TDS_MONEY4) ); return sizeof(TDS_MONEY4); } break; case SYBDATETIME: return string_to_datetime(src, SYBDATETIME, cr); break; case SYBDATETIME4: return string_to_datetime(src, SYBDATETIME4, cr); break; case SYBNUMERIC: case SYBDECIMAL: return string_to_numeric(src, src+srclen, cr); break; case SYBUNIQUE: { unsigned n = 0; char c; /* parse formats like XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -