📄 convert.c
字号:
/* fix MONEY case */#if !defined(WORDS_BIGENDIAN) && defined(HAVE_INT64) if (length > 0 && desttype == SYBMONEY) { cr->m.mny = ((TDS_UINT8) cr->m.mny) >> 32 | (cr->m.mny << 32); }#endif return length;}static intstring_to_datetime(const char *instr, int desttype, CONV_RESULT * cr){ enum states { GOING_IN_BLIND, PUT_NUMERIC_IN_CONTEXT, DOING_ALPHABETIC_DATE, STRING_GARBLED }; char *in; char *tok; char *lasts; char last_token[32]; int monthdone = 0; int yeardone = 0; int mdaydone = 0; struct tds_time mytime; struct tds_time *t; unsigned int dt_time; TDS_INT dt_days; int i; int current_state; memset(&mytime, '\0', sizeof(struct tds_time)); mytime.tm_mday = 1; t = &mytime; in = (char *) malloc(strlen(instr) + 1); test_alloc(in); strcpy(in, instr); tok = strtok_r(in, " ,", &lasts); current_state = GOING_IN_BLIND; while (tok != NULL) { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: current_state = %d\n", current_state); switch (current_state) { case GOING_IN_BLIND: /* If we have no idea of current context, then if we have */ /* encountered a purely alphabetic string, it MUST be an */ /* alphabetic month name or prefix... */ if (is_alphabetic(tok)) { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_alphabetic\n"); if (store_monthname(tok, t) >= 0) { monthdone++; current_state = DOING_ALPHABETIC_DATE; } else { current_state = STRING_GARBLED; } } /* ...whereas if it is numeric, it could be a number of */ /* things... */ else if (is_numeric(tok)) { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_numeric\n"); switch (strlen(tok)) { /* in this context a 4 character numeric can */ /* ONLY be the year part of an alphabetic date */ case 4: store_year(atoi(tok), t); yeardone++; current_state = DOING_ALPHABETIC_DATE; break; /* whereas these could be the hour part of a */ /* time specification ( 4 PM ) or the leading */ /* day part of an alphabetic date ( 15 Jan ) */ case 2: case 1: strcpy(last_token, tok); current_state = PUT_NUMERIC_IN_CONTEXT; break; /* this must be a [YY]YYMMDD date */ case 6: case 8: if (store_yymmdd_date(tok, t)) current_state = GOING_IN_BLIND; else current_state = STRING_GARBLED; break; /* anything else is nonsense... */ default: current_state = STRING_GARBLED; break; } } /* it could be [M]M/[D]D/[YY]YY format */ else if (is_numeric_dateformat(tok)) { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_numeric_dateformat\n"); store_numeric_date(tok, t); current_state = GOING_IN_BLIND; } else if (is_dd_mon_yyyy(tok)) { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_dd_mon_yyyy\n"); store_dd_mon_yyy_date(tok, t); current_state = GOING_IN_BLIND; } else if (is_timeformat(tok)) { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_timeformat\n"); store_time(tok, t); current_state = GOING_IN_BLIND; } else { tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: string_garbled\n"); current_state = STRING_GARBLED; } break; /* end of GOING_IN_BLIND */ case DOING_ALPHABETIC_DATE: if (is_alphabetic(tok)) { if (!monthdone && store_monthname(tok, t) >= 0) { monthdone++; if (monthdone && yeardone && mdaydone) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } else { current_state = STRING_GARBLED; } } else if (is_numeric(tok)) { if (mdaydone && yeardone) current_state = STRING_GARBLED; else switch (strlen(tok)) { case 4: store_year(atoi(tok), t); yeardone++; if (monthdone && yeardone && mdaydone) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; break; case 2: case 1: if (!mdaydone) { store_mday(tok, t); mdaydone++; if (monthdone && yeardone && mdaydone) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } else { store_year(atoi(tok), t); yeardone++; if (monthdone && yeardone && mdaydone) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } break; default: current_state = STRING_GARBLED; } } else { current_state = STRING_GARBLED; } break; /* end of DOING_ALPHABETIC_DATE */ case PUT_NUMERIC_IN_CONTEXT: if (is_alphabetic(tok)) { if (store_monthname(tok, t) >= 0) { store_mday(last_token, t); mdaydone++; monthdone++; if (monthdone && yeardone && mdaydone) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; } else if (is_ampm(tok)) { store_hour(last_token, tok, t); current_state = GOING_IN_BLIND; } else { current_state = STRING_GARBLED; } } else if (is_numeric(tok)) { switch (strlen(tok)) { case 4: case 2: store_mday(last_token, t); mdaydone++; store_year(atoi(tok), t); yeardone++; if (monthdone && yeardone && mdaydone) current_state = GOING_IN_BLIND; else current_state = DOING_ALPHABETIC_DATE; break; default: current_state = STRING_GARBLED; } } else { current_state = STRING_GARBLED; } break; /* end of PUT_NUMERIC_IN_CONTEXT */ case STRING_GARBLED: tdsdump_log(TDS_DBG_INFO1, "error_handler: Attempt to convert data stopped by syntax error in source field \n"); free(in); return TDS_CONVERT_SYNTAX; } tok = strtok_r(NULL, " ,", &lasts); } i = (t->tm_mon - 13) / 12; dt_days = 1461 * (t->tm_year + 300 + i) / 4 + (367 * (t->tm_mon - 1 - 12 * i)) / 12 - (3 * ((t->tm_year + 400 + i) / 100)) / 4 + t->tm_mday - 109544; free(in); /* TODO check for overflow */ if (desttype == SYBDATETIME) { cr->dt.dtdays = dt_days; dt_time = (t->tm_hour * 60 + t->tm_min) * 60 + t->tm_sec; cr->dt.dttime = dt_time * 300 + (t->tm_ms * 300 + 150) / 1000; return sizeof(TDS_DATETIME); } else { /* SYBDATETIME4 */ cr->dt4.days = dt_days; cr->dt4.minutes = t->tm_hour * 60 + t->tm_min; return sizeof(TDS_DATETIME4); }}static intstringz_to_numeric(const char *instr, CONV_RESULT * cr){ return string_to_numeric(instr, instr + strlen(instr), cr);}static intstring_to_numeric(const char *instr, const char *pend, CONV_RESULT * cr){ char mynumber[(MAXPRECISION + 7) / 8 * 8 + 8]; /* num packaged 8 digit, see below for detail */ TDS_UINT packed_num[(MAXPRECISION + 7) / 8]; char *ptr; const char *pstr; int old_digits_left, digits_left, digit_found = 0; int i = 0; int j = 0; int bytes, places; unsigned char sign; /* FIXME: application can pass invalid value for precision and scale ?? */ if (cr->n.precision > 77) return TDS_CONVERT_FAIL; if (cr->n.precision == 0) cr->n.precision = 77; /* assume max precision */ if (cr->n.scale > cr->n.precision) return TDS_CONVERT_FAIL; /* skip leading blanks */ for (pstr = instr;; ++pstr) { if (pstr == pend) return TDS_CONVERT_SYNTAX; if (*pstr != ' ') break; } sign = 0; if (*pstr == '-' || *pstr == '+') { /* deal with a leading sign */ if (*pstr == '-') sign = 1; pstr++; } cr->n.array[0] = sign; /* * skip leading zeroes * Not skipping them cause numbers like "000000000000" to * appear like overflow */ for (; pstr != pend && *pstr == '0'; ++pstr) digit_found = 1; /* * Having disposed of any sign and leading blanks, * vet the digit string, counting places before and after * the decimal point. Dispense with trailing blanks, if any. */ ptr = mynumber; for (i = 0; i < 8; ++i) *ptr++ = '0'; places = 0; old_digits_left = 0; digits_left = cr->n.precision - cr->n.scale; for (; pstr != pend; ++pstr) { /* deal with the rest */ if (*pstr >= '0' && *pstr <= '9') { /* it's a number */ /* copy digit to destination */ if (--digits_left >= 0) *ptr++ = *pstr; digit_found = 1; } else if (*pstr == '.') { /* found a decimal point */ if (places) /* found a decimal point previously: return error */ return TDS_CONVERT_SYNTAX; old_digits_left = digits_left; digits_left = cr->n.scale; places = 1; } else if (*pstr == ' ') { for (; pstr != pend && *pstr == ' '; ++pstr) ; /* skip contiguous blanks */ if (pstr == pend) break; /* success: found only trailing blanks */ return TDS_CONVERT_SYNTAX; /* bzzt: found something after the blank(s) */ } else { /* first invalid character */ return TDS_CONVERT_SYNTAX; } } /* no digits? no number! */ if (!digit_found) return TDS_CONVERT_SYNTAX; if (!places) { old_digits_left = digits_left; digits_left = cr->n.scale; } /* too many digits, error */ if (old_digits_left < 0) return TDS_CONVERT_OVERFLOW; /* fill up decimal digits */ while (--digits_left >= 0) *ptr++ = '0'; /* * Packaged number explanation: * We package 8 decimal digits in one number. * Because 10^8 = 5^8 * 2^8 = 5^8 * 256, dividing 10^8 by 256 leaves no remainder. * We can thus split it into bytes in an optimized way. */ /* transform to packaged one */ j = -1; ptr -= 8; do { TDS_UINT n = *ptr++; for (i = 1; i < 8; ++i) n = n * 10 + *ptr++; /* fix packet number and store */ packed_num[++j] = n - ((TDS_UINT) '0' * 11111111lu); ptr -= 16; } while (ptr > mynumber); memset(cr->n.array + 1, 0, sizeof(cr->n.array) - 1); bytes = tds_numeric_bytes_per_prec[cr->n.precision]; while (j > 0 && !packed_num[j]) --j; for (;;) { char is_zero = 1; TDS_UINT carry = 0; i = j; if (!packed_num[j]) --j; do { TDS_UINT tmp = packed_num[i]; if (tmp) is_zero = 0; /* divide for 256 for find another byte */ /* * carry * (25u*25u*25u*25u) = carry * 10^8 / 256u * using unsigned number is just an optimization * compiler can translate division to a shift and remainder * to a binary AND */ packed_num[i] = carry * (25u * 25u * 25u * 25u) + tmp / 256u; carry = tmp % 256u; } while(--i >= 0); if (is_zero) break; /* * source number is limited to 38 decimal digit * 10^39-1 < 2^128 (16 byte) so this cannot make an overflow */ cr->n.array[--bytes] = carry; } return sizeof(TDS_NUMERIC);}static intis_numeric_dateformat(const char *t){ const char *instr; int ret = 1; int slashes = 0; int hyphens = 0; int periods = 0; int digits = 0; for (instr = t; *instr; instr++) { if (!isdigit((unsigned char) *instr) && *instr != '/' && *instr != '-' && *instr != '.') { ret = 0; break; } if (*instr == '/') slashes++; else if (*instr == '-') hyphens++; else if (*instr == '.') periods++; else digits++; } if (hyphens + slashes + periods != 2) ret = 0; if (hyphens == 1 || slashes == 1 || periods == 1) ret = 0; if (digits < 4 || digits > 8) ret = 0; return (ret);}/* This function will check if an alphanumeric string *//* holds a date in any of the following formats : *//* DD-MON-YYYY *//* DD-MON-YY *//* DDMONYY *//* DDMONYYYY */static intis_dd_mon_yyyy(char *t){ char *instr; char month[4]; instr = t; if (!isdigit((unsigned char) *instr)) return (0); instr++; if (!isdigit((unsigned char) *instr)) return (0); instr++; if (*instr == '-') { instr++; strncpy(month, instr, 3); month[3] = '\0'; if (!is_monthname(month)) return (0); instr += 3; if (*instr != '-') return (0); instr++; if (!isdigit((unsigned char) *instr)) return (0); instr++; if (!isdigit((unsigned char) *instr)) return (0); instr++; if (*instr) { if (!isdigit((unsigned char) *instr)) return (0); instr++; if (!isdigit((unsigned char) *instr)) return (0); } } else { strncpy(month, instr, 3); month[3] = '\0'; if (!is_monthname(month)) return (0); instr += 3; if (!isdigit((unsigned char) *instr)) return (0); instr++; if (!isdigit((unsigned char) *instr)) return (0); instr++; if (*instr) { if (!isdigit((unsigned char) *instr)) return (0); instr++; if (!isdigit((unsigned char) *instr)) return (0); } } return (1);}static intis_ampm(const char *datestr){ int ret = 0; if (strcasecmp(datestr, "am") == 0) ret = 1; else if (strcasecmp(datestr, "pm") == 0) ret = 1; else ret = 0; return ret;}static intis_alphabetic(const char *datestr){ const char *s; int ret = 1; for (s = datestr; *s; s++) { if (!isalpha((unsigned char) *s))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -