NCBI C++ ToolKit
convert.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Brian Bruns
3  * Copyright (C) 2010-2015 Frediano Ziglio
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include <config.h>
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 
26 #include <freetds/time.h>
27 
28 #include <assert.h>
29 #include <ctype.h>
30 
31 #if HAVE_ERRNO_H
32 #include <errno.h>
33 #endif /* HAVE_ERRNO_H */
34 
35 #if HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif /* HAVE_STDLIB_H */
38 
39 #if HAVE_STRING_H
40 #include <string.h>
41 #endif /* HAVE_STRING_H */
42 
43 #if HAVE_STRINGS_H
44 #include <strings.h>
45 #endif /* HAVE_STRINGS_H */
46 
47 #include <freetds/tds.h>
48 #include <freetds/convert.h>
49 #include <freetds/bytes.h>
50 #include "replacements.h"
51 
52 typedef unsigned short utf16_t;
53 
54 struct tds_time
55 {
56  int tm_year; /**< year (0=1900) */
57  int tm_mon; /**< month (0-11) */
58  int tm_mday; /**< month day (1-31) */
59  int tm_hour; /**< hours (0-23) */
60  int tm_min; /**< minutes (0-59) */
61  int tm_sec; /**< seconds (0-59) */
62  int tm_ns; /**< nanoseconds (0-999999999) */
63 };
64 
65 static TDS_INT tds_convert_int(TDS_INT num, int desttype, CONV_RESULT * cr);
66 static TDS_INT tds_convert_int1(const TDS_TINYINT * src, int desttype, CONV_RESULT * cr);
67 static TDS_INT tds_convert_int2(const TDS_SMALLINT * src, int desttype, CONV_RESULT * cr);
68 static TDS_INT tds_convert_uint2(const TDS_USMALLINT * src, int desttype, CONV_RESULT * cr);
69 static TDS_INT tds_convert_int4(const TDS_INT* src, int desttype, CONV_RESULT * cr);
70 static TDS_INT tds_convert_uint4(const TDS_UINT * src, int desttype, CONV_RESULT * cr);
71 static TDS_INT tds_convert_int8(const TDS_INT8 * src, int desttype, CONV_RESULT * cr);
72 static TDS_INT tds_convert_uint8(const TDS_UINT8 * src, int desttype, CONV_RESULT * cr);
73 static int string_to_datetime(const char *datestr, TDS_UINT len, int desttype, CONV_RESULT * cr);
74 static bool is_dd_mon_yyyy(char *t);
75 static int store_dd_mon_yyy_date(char *datestr, struct tds_time *t);
76 static const char *parse_numeric(const char *buf, const char *pend,
77  bool * p_negative, size_t *p_digits, size_t *p_decimals);
78 
79 #define test_alloc(x) {if ((x)==NULL) return TDS_CONVERT_NOMEM;}
80 
81 #define IS_TINYINT(x) ( 0 <= (x) && (x) <= 0xff )
82 #define IS_SMALLINT(x) ( -32768 <= (x) && (x) <= 32767 )
83 #define IS_USMALLINT(x) ( 0 <= (x) && (x) <= 65535 )
84 /*
85  * f77: I don't write -2147483648, some compiler seem to have some problem
86  * with this constant although is a valid 32bit value
87  */
88 #define TDS_INT_MIN (-2147483647l-1l)
89 #define TDS_INT_MAX 2147483647l
90 #define IS_INT(x) (TDS_INT_MIN <= (x) && (x) <= TDS_INT_MAX)
91 
92 #define TDS_UINT_MAX 4294967295lu
93 #define IS_UINT(x) (0 <= (x) && (x) <= TDS_UINT_MAX)
94 
95 #define TDS_INT8_MAX ((((TDS_INT8) 0x7fffffffl) << 32) + (TDS_INT8) 0xfffffffflu)
96 #define TDS_INT8_MIN (-TDS_INT8_MAX - (TDS_INT8) 1)
97 #define IS_INT8(x) (TDS_INT8_MIN <= (x) && (x) <= TDS_INT8_MAX)
98 
99 #define TDS_UINT8_MAX ((((TDS_UINT8) 0xfffffffflu) << 32) + 0xfffffffflu)
100 #define IS_UINT8(x) (0 <= (x) && (x) <= TDS_UINT8_MAX)
101 
102 #define TDS_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
103 
104 #define BIGDATETIME_BIAS 693961
105 
106 /**
107  * \ingroup libtds
108  * \defgroup convert Conversion
109  * Conversions between datatypes. Supports, for example, dbconvert().
110  */
111 
112 /**
113  * \addtogroup convert
114  * @{
115  */
116 
117 /**
118  * convert a number in string to a TDSNUMERIC
119  * @return sizeof(TDS_NUMERIC) on success, TDS_CONVERT_* failure code on failure
120  */
121 static int string_to_numeric(const char *instr, const char *pend, CONV_RESULT * cr);
122 
123 /**
124  * convert a zero terminated string to NUMERIC
125  * @return sizeof(TDS_NUMERIC) on success, TDS_CONVERT_* failure code on failure
126  */
127 static int stringz_to_numeric(const char *instr, CONV_RESULT * cr);
128 
129 static TDS_INT string_to_int(const char *buf, const char *pend, TDS_INT * res);
130 static TDS_INT string_to_int8(const char *buf, const char *pend, TDS_INT8 * res);
131 static TDS_INT string_to_uint8(const char *buf, const char *pend, TDS_UINT8 * res);
132 static TDS_INT string_to_float(const TDS_CHAR * src, TDS_UINT srclen, int desttype, CONV_RESULT * cr);
133 
134 static int store_hour(const char *, const char *, struct tds_time *);
135 static int store_time(const char *, struct tds_time *);
136 static int store_yymmdd_date(const char *, struct tds_time *);
137 static int store_monthname(const char *, struct tds_time *);
138 static int store_numeric_date(const char *, struct tds_time *);
139 static int store_mday(const char *, struct tds_time *);
140 static int store_year(int, struct tds_time *);
141 
142 /* static int days_this_year (int years); */
143 static bool is_timeformat(const char *);
144 static bool is_numeric(const char *);
145 static bool is_alphabetic(const char *);
146 static bool is_ampm(const char *);
147 #define is_monthname(s) (store_monthname(s, NULL) >= 0)
148 static bool is_numeric_dateformat(const char *);
149 
150 #if 0
151 static TDS_UINT utf16len(const utf16_t * s);
152 static const char *tds_prtype(int token);
153 #endif
154 
155 const char tds_hex_digits[] = "0123456789abcdef";
156 
157 /**
158  * Copy a terminated string to result and return len or TDS_CONVERT_NOMEM
159  */
160 static TDS_INT
161 string_to_result_(int desttype, const char *s, CONV_RESULT * cr)
162 {
163  size_t len = strlen(s);
164 
165  if (desttype != TDS_CONVERT_CHAR) {
166  cr->c = tds_new(TDS_CHAR, len + 1);
167  test_alloc(cr->c);
168  memcpy(cr->c, s, len + 1);
169  } else {
170  memcpy(cr->cc.c, s, len < cr->cc.len ? len : cr->cc.len);
171  }
172  return (TDS_INT)len;
173 }
174 
175 #define string_to_result(s, cr) \
176  string_to_result_(desttype, s, cr)
177 
178 /**
179  * Copy binary data to to result and return len or TDS_CONVERT_NOMEM
180  */
181 static TDS_INT
182 binary_to_result(int desttype, const void *data, size_t len, CONV_RESULT * cr)
183 {
184  if (desttype != TDS_CONVERT_BINARY) {
185  cr->ib = tds_new(TDS_CHAR, len);
186  test_alloc(cr->ib);
187  memcpy(cr->ib, data, len);
188  } else {
189  memcpy(cr->cb.ib, data, len < cr->cb.len ? len : cr->cb.len);
190  }
191  return (TDS_INT)len;
192 }
193 
194 /* "N" versions are safe to list due to iconv calls elsewhere. */
195 #define CASE_ALL_CHAR \
196  SYBCHAR: case SYBVARCHAR: case SYBTEXT: case XSYBCHAR: \
197  case XSYBVARCHAR: case SYBNVARCHAR: case SYBNTEXT: case XSYBNCHAR: \
198  case XSYBNVARCHAR
199 #define CASE_ALL_BINARY \
200  SYBBINARY: case SYBVARBINARY: case SYBIMAGE: case XSYBBINARY: case XSYBVARBINARY: \
201  case SYBLONGBINARY: case TDS_CONVERT_BINARY
202 
203 /* TODO implement me */
204 /*
205 static TDS_INT
206 tds_convert_ntext(int srctype,TDS_CHAR *src,TDS_UINT srclen,
207  int desttype, CONV_RESULT *cr)
208 {
209  return TDS_CONVERT_NOAVAIL;
210 }
211 */
212 
213 static TDS_INT
214 tds_convert_binary(const TDS_UCHAR * src, TDS_INT srclen, int desttype, CONV_RESULT * cr)
215 {
216  int cplen;
217  int s;
218  char *c;
219 
220  switch (desttype) {
221  case TDS_CONVERT_CHAR:
222  cplen = srclen * 2;
223  if ((TDS_UINT)cplen > cr->cc.len)
224  cplen = cr->cc.len;
225 
226  c = cr->cc.c;
227  for (s = 0; cplen >= 2; ++s, cplen -= 2) {
228  *c++ = tds_hex_digits[src[s]>>4];
229  *c++ = tds_hex_digits[src[s]&0xF];
230  }
231  if (cplen)
232  *c = tds_hex_digits[src[s]>>4];
233  return srclen * 2;
234 
235  case CASE_ALL_CHAR:
236 
237  /*
238  * NOTE: Do not prepend 0x to string.
239  * The libraries all expect a bare string, without a 0x prefix.
240  * Applications such as isql and query analyzer provide the "0x" prefix.
241  */
242 
243  /* 2 * source length + 1 for terminator */
244 
245  cr->c = tds_new(TDS_CHAR, (srclen * 2) + 1);
246  test_alloc(cr->c);
247 
248  c = cr->c;
249 
250  for (s = 0; s < srclen; s++) {
251  *c++ = tds_hex_digits[src[s]>>4];
252  *c++ = tds_hex_digits[src[s]&0xF];
253  }
254 
255  *c = '\0';
256  return (srclen * 2);
257  break;
258  case SYBINT1:
259  case SYBUINT1:
260  case SYBINT2:
261  case SYBUINT2:
262  case SYBINT4:
263  case SYBUINT4:
264  case SYBINT8:
265  case SYBUINT8:
266  case SYBMONEY4:
267  case SYBMONEY:
268  case SYBREAL:
269  case SYBFLT8:
270  cplen = tds_get_size_by_type(desttype);
271  if (srclen >= cplen)
272  srclen = cplen;
273  memcpy(cr, src, srclen);
274  memset(((char*) cr) + srclen, 0, cplen - srclen);
275  return cplen;
276  break;
277 
278  /* conversions not allowed */
279  case SYBDATETIME4:
280  case SYBDATETIME:
281  case SYBDATETIMN:
282 
283  /* TODO should we do some test for these types or work as ints ?? */
284  case SYBDECIMAL:
285  case SYBNUMERIC:
286  case SYBBIT:
287  case SYBBITN:
288 
289  default:
290  break;
291  }
292  return TDS_CONVERT_NOAVAIL;
293 }
294 
295 ssize_t
296 tds_char2hex(TDS_CHAR *dest, size_t destlen,
297  const TDS_CHAR * src, size_t srclen)
298 {
299  size_t i;
300  unsigned char hex1, c = 0;
301 
302  /* if srclen if odd we must add a "0" before ... */
303  i = 0; /* number where to start converting */
304  if (srclen & 1) {
305  ++srclen;
306  i = 1;
307  --src;
308  }
309  for (; i < srclen; ++i) {
310  hex1 = src[i];
311 
312  if ('0' <= hex1 && hex1 <= '9')
313  hex1 &= 0x0f;
314  else {
315  hex1 &= 0x20 ^ 0xff; /* mask off 0x20 to ensure upper case */
316  if ('A' <= hex1 && hex1 <= 'F') {
317  hex1 -= ('A' - 10);
318  } else {
320  "error_handler: attempt to convert data stopped by syntax error in source field \n");
321  return TDS_CONVERT_SYNTAX;
322  }
323  }
324  assert(hex1 < 0x10);
325 
326  if ((i/2u) >= destlen)
327  continue;
328 
329  if (i & 1)
330  dest[i / 2u] = c | hex1;
331  else
332  c = hex1 << 4;
333  }
334  return srclen / 2u;
335 }
336 
337 static TDS_INT
338 tds_convert_char(const TDS_CHAR * src, TDS_UINT srclen, int desttype, CONV_RESULT * cr)
339 {
340  unsigned int i;
341 
342  TDS_INT8 mymoney;
343  char mynumber[28];
344 
345  TDS_INT tds_i;
346  TDS_INT8 tds_i8;
347  TDS_UINT8 tds_ui8;
348  TDS_INT rc;
349 
350  bool negative;
351  size_t digits, decimals;
352 
353  switch (desttype) {
354  case TDS_CONVERT_CHAR:
355  memcpy(cr->cc.c, src, srclen < cr->cc.len ? srclen : cr->cc.len);
356  return srclen;
357 
358  case CASE_ALL_CHAR:
359  cr->c = tds_new(TDS_CHAR, srclen + 1);
360  test_alloc(cr->c);
361  memcpy(cr->c, src, srclen);
362  cr->c[srclen] = 0;
363  return srclen;
364  break;
365 
366  case SYBINT1:
367  case SYBUINT1:
368  if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)
369  return rc;
370  if (!IS_TINYINT(tds_i))
371  return TDS_CONVERT_OVERFLOW;
372  cr->ti = tds_i;
373  return sizeof(TDS_TINYINT);
374  break;
375  case SYBINT2:
376  if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)
377  return rc;
378  if (!IS_SMALLINT(tds_i))
379  return TDS_CONVERT_OVERFLOW;
380  cr->si = tds_i;
381  return sizeof(TDS_SMALLINT);
382  break;
383  case SYBUINT2:
384  if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)
385  return rc;
386  if (!IS_USMALLINT(tds_i))
387  return TDS_CONVERT_OVERFLOW;
388  cr->usi = (TDS_USMALLINT) tds_i;
389  return sizeof(TDS_USMALLINT);
390  break;
391  case SYBINT4:
392  if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)
393  return rc;
394  cr->i = tds_i;
395  return sizeof(TDS_INT);
396  break;
397  case SYBUINT4:
398  if ((rc = string_to_int8(src, src + srclen, &tds_i8)) < 0)
399  return rc;
400  if (!IS_UINT(tds_i8))
401  return TDS_CONVERT_OVERFLOW;
402  cr->ui = (TDS_UINT) tds_i8;
403  return sizeof(TDS_UINT);
404  break;
405  case SYBINT8:
406  if ((rc = string_to_int8(src, src + srclen, &tds_i8)) < 0)
407  return rc;
408  cr->bi = tds_i8;
409  return sizeof(TDS_INT8);
410  break;
411  case SYBUINT8:
412  if ((rc = string_to_uint8(src, src + srclen, &tds_ui8)) < 0)
413  return rc;
414  cr->ubi = tds_ui8;
415  return sizeof(TDS_UINT8);
416  break;
417  case SYBFLT8:
418  case SYBREAL:
419  return string_to_float(src, srclen, desttype, cr);
420  break;
421  case SYBBIT:
422  case SYBBITN:
423  if ((rc = string_to_int(src, src + srclen, &tds_i)) < 0)
424  return rc;
425  cr->ti = tds_i ? 1 : 0;
426  return sizeof(TDS_TINYINT);
427  break;
428  case SYBMONEY:
429  case SYBMONEY4:
430 
431  src = parse_numeric(src, src + srclen, &negative, &digits, &decimals);
432  if (!src)
433  return TDS_CONVERT_SYNTAX;
434  if (digits > 18)
435  return TDS_CONVERT_OVERFLOW;
436 
437  i = 0;
438  if (negative)
439  mynumber[i++] = '-';
440  for (; digits; --digits)
441  mynumber[i++] = *src++;
442  src++;
443  for (digits = 0; digits < 4 && digits < decimals; ++digits)
444  mynumber[i++] = *src++;
445  for (; digits < 4; ++digits)
446  mynumber[i++] = '0';
447 
448  /* convert number and check for overflow */
449  if (string_to_int8(mynumber, mynumber + i, &mymoney) < 0)
450  return TDS_CONVERT_OVERFLOW;
451 
452  if (desttype == SYBMONEY) {
453  cr->m.mny = mymoney;
454  return sizeof(TDS_MONEY);
455  } else {
456  if (!IS_INT(mymoney))
457  return TDS_CONVERT_OVERFLOW;
458  cr->m4.mny4 = (TDS_INT) mymoney;
459  return sizeof(TDS_MONEY4);
460  }
461  break;
462  case SYBDATETIME:
463  case SYBDATETIME4:
464  case SYBMSTIME:
465  case SYBMSDATE:
466  case SYBMSDATETIME2:
467  case SYBMSDATETIMEOFFSET:
468  case SYBTIME:
469  case SYBDATE:
470  case SYB5BIGTIME:
471  case SYB5BIGDATETIME:
472  return string_to_datetime(src, srclen, desttype, cr);
473  break;
474  case SYBNUMERIC:
475  case SYBDECIMAL:
476  return string_to_numeric(src, src + srclen, cr);
477  break;
478  case SYBUNIQUE:{
479  unsigned n = 0;
480  char c;
481 
482  /*
483  * format: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
484  * or {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
485  * or XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX
486  * or {XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX}
487  * SQL seem to ignore the additional braces.
488  */
489  if (srclen < (32 + 3))
490  return TDS_CONVERT_SYNTAX;
491 
492  if (src[0] == '{') {
493  TDS_UINT last = (src[8+1 + 4+1 + 4+1 + 4 + 1] == '-') ? 32+4+1 : 32+3+1;
494  if (srclen <= last || src[last] != '}')
495  return TDS_CONVERT_SYNTAX;
496  ++src;
497  }
498 
499  /*
500  * Test each character and get value.
501  * sscanf works if the number terminates with less digits.
502  */
503  for (i = 0; i < 32 + 3; ++i) {
504  c = src[i];
505  switch (i) {
506  case 8:
507  if (c != '-')
508  return TDS_CONVERT_SYNTAX;
509  cr->u.Data1 = n;
510  n = 0;
511  break;
512  case 8+1 + 4:
513  if (c != '-')
514  return TDS_CONVERT_SYNTAX;
515  cr->u.Data2 = n;
516  n = 0;
517  break;
518  case 8+1 + 4+1 + 4:
519  if (c != '-')
520  return TDS_CONVERT_SYNTAX;
521  cr->u.Data3 = n;
522  n = 0;
523  break;
524  case 8+1 + 4+1 + 4+1 + 4:
525  /* skip last (optional) dash */
526  if (c == '-') {
527  if (--srclen < 32 + 3)
528  return TDS_CONVERT_SYNTAX;
529  c = (++src)[i];
530  }
531  /* fall through */
532  default:
533  n = n << 4;
534  if (c >= '0' && c <= '9')
535  n += c - '0';
536  else {
537  c &= 0x20 ^ 0xff;
538  if (c >= 'A' && c <= 'F')
539  n += c - ('A' - 10);
540  else
541  return TDS_CONVERT_SYNTAX;
542  }
543  if (i > (16 + 2) && !(i & 1)) {
544  cr->u.Data4[(i >> 1) - 10] = n;
545  n = 0;
546  }
547  }
548  }
549  }
550  return sizeof(TDS_UNIQUE);
551  default:
552  return TDS_CONVERT_NOAVAIL;
553  break;
554  } /* end switch */
555 } /* tds_convert_char */
556 
557 static TDS_INT
558 tds_convert_bit(const TDS_CHAR * src, int desttype, CONV_RESULT * cr)
559 {
560  return tds_convert_int(src[0] ? 1 : 0, desttype, cr);
561 }
562 
563 static TDS_INT
564 tds_convert_int1(const TDS_TINYINT * src, int desttype, CONV_RESULT * cr)
565 {
566  return tds_convert_int(*src, desttype, cr);
567 }
568 
569 static TDS_INT
570 tds_convert_int2(const TDS_SMALLINT * src, int desttype, CONV_RESULT * cr)
571 {
572  return tds_convert_int(*src, desttype, cr);
573 }
574 
575 static TDS_INT
576 tds_convert_uint2(const TDS_USMALLINT * src, int desttype, CONV_RESULT * cr)
577 {
578  return tds_convert_int(*src, desttype, cr);
579 }
580 
581 static TDS_INT
582 tds_convert_int4(const TDS_INT * src, int desttype, CONV_RESULT * cr)
583 {
584  return tds_convert_int(*src, desttype, cr);
585 }
586 
587 static TDS_INT
588 tds_convert_uint4(const TDS_UINT * src, int desttype, CONV_RESULT * cr)
589 {
590  TDS_UINT8 num;
591 
592  num = *src;
593  return tds_convert_uint8(&num, desttype, cr);
594 }
595 
596 static TDS_INT
597 tds_convert_int_numeric(unsigned char scale,
598  unsigned char sign, TDS_UINT num, CONV_RESULT * cr)
599 {
600  unsigned char orig_prec = cr->n.precision, orig_scale = cr->n.scale;
601  cr->n.precision = 10;
602  cr->n.scale = scale;
603  cr->n.array[0] = sign;
604  cr->n.array[1] = 0;
605  TDS_PUT_UA4BE(&(cr->n.array[2]), num);
606  return tds_numeric_change_prec_scale(&(cr->n), orig_prec, orig_scale);
607 }
608 
609 static TDS_INT
610 tds_convert_int8_numeric(unsigned char scale,
611  unsigned char sign, TDS_UINT8 num, CONV_RESULT * cr)
612 {
613  unsigned char orig_prec = cr->n.precision, orig_scale = cr->n.scale;
614  cr->n.precision = 20;
615  cr->n.scale = scale;
616  cr->n.array[0] = sign;
617  cr->n.array[1] = 0;
618  TDS_PUT_UA4BE(&(cr->n.array[2]), (TDS_UINT) (num >> 32));
619  TDS_PUT_UA4BE(&(cr->n.array[6]), (TDS_UINT) num);
620  return tds_numeric_change_prec_scale(&(cr->n), orig_prec, orig_scale);
621 }
622 
623 static TDS_INT
624 tds_convert_int(TDS_INT num, int desttype, CONV_RESULT * cr)
625 {
626  TDS_CHAR tmp_str[16];
627 
628  switch (desttype) {
629  case TDS_CONVERT_CHAR:
630  case CASE_ALL_CHAR:
631  sprintf(tmp_str, "%d", num);
632  return string_to_result(tmp_str, cr);
633  break;
634  case SYBINT1:
635  case SYBUINT1:
636  if (!IS_TINYINT(num))
637  return TDS_CONVERT_OVERFLOW;
638  cr->ti = (TDS_TINYINT) num;
639  return sizeof(TDS_TINYINT);
640  break;
641  case SYBINT2:
642  if (!IS_SMALLINT(num))
643  return TDS_CONVERT_OVERFLOW;
644  cr->si = num;
645  return sizeof(TDS_SMALLINT);
646  break;
647  case SYBUINT2:
648  if (!IS_USMALLINT(num))
649  return TDS_CONVERT_OVERFLOW;
650  cr->usi = (TDS_USMALLINT) num;
651  return sizeof(TDS_USMALLINT);
652  break;
653  case SYBINT4:
654  cr->i = num;
655  return sizeof(TDS_INT);
656  break;
657  case SYBUINT4:
658  if (num < 0)
659  return TDS_CONVERT_OVERFLOW;
660  cr->ui = (TDS_UINT) num;
661  return sizeof(TDS_UINT);
662  break;
663  case SYBINT8:
664  cr->bi = num;
665  return sizeof(TDS_INT8);
666  break;
667  case SYBUINT8:
668  if (num < 0)
669  return TDS_CONVERT_OVERFLOW;
670  cr->ubi = (TDS_UINT8) num;
671  return sizeof(TDS_UINT8);
672  break;
673  case SYBBIT:
674  case SYBBITN:
675  cr->ti = num ? 1 : 0;
676  return sizeof(TDS_TINYINT);
677  break;
678  case SYBFLT8:
679  cr->f = num;
680  return sizeof(TDS_FLOAT);
681  break;
682  case SYBREAL:
683  cr->r = (TDS_REAL) num;
684  return sizeof(TDS_REAL);
685  break;
686  case SYBMONEY4:
687  if (num > 214748 || num < -214748)
688  return TDS_CONVERT_OVERFLOW;
689  cr->m4.mny4 = num * 10000;
690  return sizeof(TDS_MONEY4);
691  break;
692  case SYBMONEY:
693  cr->m.mny = (TDS_INT8) num *10000;
694 
695  return sizeof(TDS_MONEY);
696  break;
697  case SYBNUMERIC:
698  case SYBDECIMAL:
699  if (num < 0)
700  return tds_convert_int_numeric(0, 1, (TDS_UINT) -num, cr);
701  return tds_convert_int_numeric(0, 0, (TDS_UINT) num, cr);
702  break;
703  /* handled by upper layer */
704  case CASE_ALL_BINARY:
705  /* conversions not allowed */
706  case SYBUNIQUE:
707  case SYBDATETIME4:
708  case SYBDATETIME:
709  case SYBDATETIMN:
710  default:
711  break;
712  }
713  return TDS_CONVERT_NOAVAIL;
714 }
715 
716 static TDS_INT
717 tds_convert_int8(const TDS_INT8 *src, int desttype, CONV_RESULT * cr)
718 {
719  TDS_INT8 buf;
720  TDS_CHAR tmp_str[24];
721 
722  memcpy(&buf, src, sizeof(buf));
723  if (IS_INT(buf))
724  return tds_convert_int((TDS_INT) buf, desttype, cr);
725 
726  switch (desttype) {
727  case TDS_CONVERT_CHAR:
728  case CASE_ALL_CHAR:
729  sprintf(tmp_str, "%" PRId64, buf);
730  return string_to_result(tmp_str, cr);
731  break;
732  case SYBINT1:
733  case SYBUINT1:
734  case SYBINT2:
735  case SYBUINT2:
736  case SYBINT4:
737  case SYBMONEY4:
738  return TDS_CONVERT_OVERFLOW;
739  break;
740  case SYBUINT4:
741  if (!IS_UINT(buf))
742  return TDS_CONVERT_OVERFLOW;
743  cr->ui = (TDS_UINT) buf;
744  return sizeof(TDS_UINT);
745  break;
746  case SYBINT8:
747  cr->bi = buf;
748  return sizeof(TDS_INT8);
749  break;
750  case SYBUINT8:
751  if (buf < 0)
752  return TDS_CONVERT_OVERFLOW;
753  cr->ubi = (TDS_UINT8) buf;
754  return sizeof(TDS_UINT8);
755  break;
756  case SYBBIT:
757  case SYBBITN:
758  /* this cannot be 0 as already tested above */
759  cr->ti = 1;
760  return sizeof(TDS_TINYINT);
761  break;
762  case SYBFLT8:
763  cr->f = (TDS_FLOAT) buf;
764  return sizeof(TDS_FLOAT);
765  break;
766  case SYBREAL:
767  cr->r = (TDS_REAL) buf;
768  return sizeof(TDS_REAL);
769  break;
770  case SYBMONEY:
771  if (buf > (TDS_INT8_MAX / 10000) || buf < (TDS_INT8_MIN / 10000))
772  return TDS_CONVERT_OVERFLOW;
773  cr->m.mny = buf * 10000;
774  return sizeof(TDS_MONEY);
775  break;
776  case SYBNUMERIC:
777  case SYBDECIMAL:
778  if (buf < 0)
779  return tds_convert_int8_numeric(0, 1, -buf, cr);
780  return tds_convert_int8_numeric(0, 0, buf, cr);
781  break;
782  /* conversions not allowed */
783  case SYBUNIQUE:
784  case SYBDATETIME4:
785  case SYBDATETIME:
786  case SYBDATETIMN:
787  default:
788  break;
789  }
790  return TDS_CONVERT_NOAVAIL;
791 }
792 
793 static TDS_INT
794 tds_convert_uint8(const TDS_UINT8 *src, int desttype, CONV_RESULT * cr)
795 {
796  TDS_UINT8 buf;
797  TDS_CHAR tmp_str[24];
798 
799  memcpy(&buf, src, sizeof(buf));
800  /* IS_INT does not work here due to unsigned/signed conversions */
801  if (buf <= (TDS_UINT8) TDS_INT_MAX)
802  return tds_convert_int((TDS_INT) buf, desttype, cr);
803 
804  switch (desttype) {
805  case TDS_CONVERT_CHAR:
806  case CASE_ALL_CHAR:
807  sprintf(tmp_str, "%" PRIu64, buf);
808  return string_to_result(tmp_str, cr);
809  break;
810  case SYBINT1:
811  case SYBUINT1:
812  case SYBINT2:
813  case SYBUINT2:
814  case SYBINT4:
815  case SYBMONEY4:
816  return TDS_CONVERT_OVERFLOW;
817  break;
818  case SYBUINT4:
819  if (!IS_UINT(buf))
820  return TDS_CONVERT_OVERFLOW;
821  cr->ui = (TDS_UINT) buf;
822  return sizeof(TDS_UINT);
823  break;
824  case SYBINT8:
825  if (buf > (TDS_UINT8) TDS_INT8_MAX)
826  return TDS_CONVERT_OVERFLOW;
827  cr->bi = (TDS_INT8) buf;
828  return sizeof(TDS_INT8);
829  break;
830  case SYBUINT8:
831  cr->ubi = buf;
832  return sizeof(TDS_UINT8);
833  break;
834  case SYBBIT:
835  case SYBBITN:
836  /* this cannot be 0 as already tested above */
837  cr->ti = 1;
838  return sizeof(TDS_TINYINT);
839  break;
840  case SYBFLT8:
841  cr->f = (TDS_FLOAT) buf;
842  return sizeof(TDS_FLOAT);
843  break;
844  case SYBREAL:
845  cr->r = (TDS_REAL) buf;
846  return sizeof(TDS_REAL);
847  break;
848  case SYBMONEY:
849  if (buf > (TDS_INT8_MAX / 10000))
850  return TDS_CONVERT_OVERFLOW;
851  cr->m.mny = buf * 10000;
852  return sizeof(TDS_MONEY);
853  break;
854  case SYBNUMERIC:
855  case SYBDECIMAL:
856  return tds_convert_int8_numeric(0, 0, buf, cr);
857  break;
858  /* conversions not allowed */
859  case SYBUNIQUE:
860  case SYBDATETIME4:
861  case SYBDATETIME:
862  case SYBDATETIMN:
863  default:
864  break;
865  }
866  return TDS_CONVERT_NOAVAIL;
867 }
868 
869 static TDS_INT
870 tds_convert_numeric(const TDS_NUMERIC * src, int desttype, CONV_RESULT * cr)
871 {
872  char tmpstr[MAXPRECISION];
873  TDS_INT i, ret;
874  TDS_INT8 bi;
875 
876  switch (desttype) {
877  case TDS_CONVERT_CHAR:
878  case CASE_ALL_CHAR:
879  if (tds_numeric_to_string(src, tmpstr) < 0)
880  return TDS_CONVERT_FAIL;
881  return string_to_result(tmpstr, cr);
882  break;
883  case SYBINT1:
884  case SYBUINT1:
885  cr->n = *src;
886  ret = tds_numeric_change_prec_scale(&(cr->n), 3, 0);
887  if (ret < 0)
888  return ret;
889  if (cr->n.array[1] || (cr->n.array[0] && cr->n.array[2]))
890  return TDS_CONVERT_OVERFLOW;
891  cr->ti = cr->n.array[2];
892  return sizeof(TDS_TINYINT);
893  break;
894  case SYBINT2:
895  cr->n = *src;
896  ret = tds_numeric_change_prec_scale(&(cr->n), 5, 0);
897  if (ret < 0)
898  return ret;
899  if (cr->n.array[1])
900  return TDS_CONVERT_OVERFLOW;
901  i = TDS_GET_UA2BE(&(cr->n.array[2]));
902  if (cr->n.array[0])
903  i = -i;
904  if (((i >> 15) ^ cr->n.array[0]) & 1)
905  return TDS_CONVERT_OVERFLOW;
906  cr->si = (TDS_SMALLINT) i;
907  return sizeof(TDS_SMALLINT);
908  break;
909  case SYBUINT2:
910  cr->n = *src;
911  ret = tds_numeric_change_prec_scale(&(cr->n), 5, 0);
912  if (ret < 0)
913  return ret;
914  if (cr->n.array[0] || cr->n.array[1])
915  return TDS_CONVERT_OVERFLOW;
916  i = TDS_GET_UA2BE(&(cr->n.array[2]));
917  cr->usi = (TDS_USMALLINT) i;
918  return sizeof(TDS_USMALLINT);
919  break;
920  case SYBINT4:
921  cr->n = *src;
922  ret = tds_numeric_change_prec_scale(&(cr->n), 10, 0);
923  if (ret < 0)
924  return ret;
925  if (cr->n.array[1])
926  return TDS_CONVERT_OVERFLOW;
927  i = TDS_GET_UA4BE(&(cr->n.array[2]));
928  if (cr->n.array[0])
929  i = -i;
930  if (((i >> 31) ^ cr->n.array[0]) & 1)
931  return TDS_CONVERT_OVERFLOW;
932  cr->i = i;
933  return sizeof(TDS_INT);
934  break;
935  case SYBUINT4:
936  cr->n = *src;
937  ret = tds_numeric_change_prec_scale(&(cr->n), 10, 0);
938  if (ret < 0)
939  return ret;
940  if (cr->n.array[0] || cr->n.array[1])
941  return TDS_CONVERT_OVERFLOW;
942  i = TDS_GET_UA4BE(&(cr->n.array[2]));
943  cr->ui = i;
944  return sizeof(TDS_UINT);
945  break;
946  case SYBINT8:
947  cr->n = *src;
948  ret = tds_numeric_change_prec_scale(&(cr->n), 20, 0);
949  if (ret < 0)
950  return ret;
951  if (cr->n.array[1])
952  return TDS_CONVERT_OVERFLOW;
953  bi = TDS_GET_UA4BE(&(cr->n.array[2]));
954  bi = (bi << 32) + TDS_GET_UA4BE(&(cr->n.array[6]));
955  if (cr->n.array[0])
956  bi = -bi;
957  if (((bi >> 63) ^ cr->n.array[0]) & 1)
958  return TDS_CONVERT_OVERFLOW;
959  cr->bi = bi;
960  return sizeof(TDS_INT8);
961  break;
962  case SYBUINT8:
963  cr->n = *src;
964  ret = tds_numeric_change_prec_scale(&(cr->n), 20, 0);
965  if (ret < 0)
966  return ret;
967  if (cr->n.array[0] || cr->n.array[1])
968  return TDS_CONVERT_OVERFLOW;
969  bi = TDS_GET_UA4BE(&(cr->n.array[2]));
970  bi = (bi << 32) + TDS_GET_UA4BE(&(cr->n.array[6]));
971  cr->ubi = bi;
972  return sizeof(TDS_UINT8);
973  break;
974  case SYBBIT:
975  case SYBBITN:
976  cr->ti = 0;
977  for (i = tds_numeric_bytes_per_prec[src->precision]; --i > 0;)
978  if (src->array[i] != 0) {
979  cr->ti = 1;
980  break;
981  }
982  return sizeof(TDS_TINYINT);
983  break;
984  case SYBMONEY4:
985  cr->n = *src;
986  ret = tds_numeric_change_prec_scale(&(cr->n), 10, 4);
987  if (ret < 0)
988  return ret;
989  if (cr->n.array[1])
990  return TDS_CONVERT_OVERFLOW;
991  i = TDS_GET_UA4BE(&(cr->n.array[2]));
992  if (cr->n.array[0])
993  i = -i;
994  if (((i >> 31) ^ cr->n.array[0]) & 1)
995  return TDS_CONVERT_OVERFLOW;
996  cr->m4.mny4 = i;
997  return sizeof(TDS_MONEY4);
998  break;
999  case SYBMONEY:
1000  cr->n = *src;
1001  ret = tds_numeric_change_prec_scale(&(cr->n), 20, 4);
1002  if (ret < 0)
1003  return ret;
1004  if (cr->n.array[1])
1005  return TDS_CONVERT_OVERFLOW;
1006  bi = TDS_GET_UA4BE(&(cr->n.array[2]));
1007  bi = (bi << 32) + TDS_GET_UA4BE(&(cr->n.array[6]));
1008  if (cr->n.array[0])
1009  bi = -bi;
1010  if (((bi >> 63) ^ cr->n.array[0]) & 1)
1011  return TDS_CONVERT_OVERFLOW;
1012  cr->m.mny = bi;
1013  return sizeof(TDS_MONEY);
1014  break;
1015  case SYBNUMERIC:
1016  case SYBDECIMAL:
1017  {
1018  unsigned char prec = cr->n.precision, scale = cr->n.scale;
1019  cr->n = *src;
1020  return tds_numeric_change_prec_scale(&(cr->n), prec, scale);
1021  }
1022  break;
1023  case SYBFLT8:
1024  if (tds_numeric_to_string(src, tmpstr) < 0)
1025  return TDS_CONVERT_FAIL;
1026  cr->f = atof(tmpstr);
1027  return 8;
1028  break;
1029  case SYBREAL:
1030  if (tds_numeric_to_string(src, tmpstr) < 0)
1031  return TDS_CONVERT_FAIL;
1032  cr->r = (TDS_REAL) atof(tmpstr);
1033  return 4;
1034  break;
1035  /* TODO conversions to money */
1036  /* conversions not allowed */
1037  case SYBUNIQUE:
1038  case SYBDATETIME4:
1039  case SYBDATETIME:
1040  case SYBDATETIMN:
1041  default:
1042  break;
1043  }
1044  return TDS_CONVERT_NOAVAIL;
1045 }
1046 
1047 static TDS_INT
1048 tds_convert_money4(const TDS_MONEY4 * src, int desttype, CONV_RESULT * cr)
1049 {
1050  TDS_MONEY4 mny;
1051  long dollars;
1052  char tmp_str[33];
1053  char *p;
1054 
1055  mny = *src;
1056  switch (desttype) {
1057  case TDS_CONVERT_CHAR:
1058  case CASE_ALL_CHAR:
1059  /*
1060  * round to 2 decimal digits
1061  * rounding with dollars = (mny.mny4 + 5000) /10000
1062  * can give arithmetic overflow so I use
1063  * dollars = (mny.mny4/50 + 1)/2
1064  */
1065  /* TODO round also all conversions to int and from money ?? */
1066  p = tmp_str;
1067  if (mny.mny4 < 0) {
1068  *p++ = '-';
1069  /* here (-mny.mny4 / 50 + 1 ) / 2 can cause overflow in -mny.mny4 */
1070  dollars = -(mny.mny4 / 50 - 1 ) / 2;
1071  } else {
1072  dollars = (mny.mny4 / 50 + 1 ) / 2;
1073  }
1074  /* print only 2 decimal digits as server does */
1075  sprintf(p, "%ld.%02lu", dollars / 100, dollars % 100);
1076  return string_to_result(tmp_str, cr);
1077  break;
1078  case SYBINT1:
1079  case SYBUINT1:
1080  dollars = mny.mny4 / 10000;
1081  if (!IS_TINYINT(dollars))
1082  return TDS_CONVERT_OVERFLOW;
1083  cr->ti = (TDS_TINYINT) dollars;
1084  return sizeof(TDS_TINYINT);
1085  break;
1086  case SYBINT2:
1087  dollars = mny.mny4 / 10000;
1088  if (!IS_SMALLINT(dollars))
1089  return TDS_CONVERT_OVERFLOW;
1090  cr->si = (TDS_SMALLINT) dollars;
1091  return sizeof(TDS_SMALLINT);
1092  break;
1093  case SYBUINT2:
1094  dollars = mny.mny4 / 10000;
1095  if (!IS_USMALLINT(dollars))
1096  return TDS_CONVERT_OVERFLOW;
1097  cr->usi = (TDS_USMALLINT) dollars;
1098  return sizeof(TDS_USMALLINT);
1099  break;
1100  case SYBINT4:
1101  cr->i = mny.mny4 / 10000;
1102  return sizeof(TDS_INT);
1103  break;
1104  case SYBUINT4:
1105  dollars = mny.mny4 / 10000;
1106  if (!IS_UINT(dollars))
1107  return TDS_CONVERT_OVERFLOW;
1108  cr->ui = (TDS_UINT) dollars;
1109  return sizeof(TDS_UINT);
1110  break;
1111  case SYBINT8:
1112  cr->bi = mny.mny4 / 10000;
1113  return sizeof(TDS_INT8);
1114  break;
1115  case SYBUINT8:
1116  dollars = mny.mny4 / 10000;
1117  if (!IS_UINT8(dollars))
1118  return TDS_CONVERT_OVERFLOW;
1119  cr->ubi = dollars;
1120  return sizeof(TDS_UINT8);
1121  break;
1122  case SYBBIT:
1123  case SYBBITN:
1124  cr->ti = mny.mny4 ? 1 : 0;
1125  return sizeof(TDS_TINYINT);
1126  break;
1127  case SYBFLT8:
1128  cr->f = ((TDS_FLOAT) mny.mny4) / 10000.0;
1129  return sizeof(TDS_FLOAT);
1130  break;
1131  case SYBREAL:
1132  cr->r = (TDS_REAL) (mny.mny4 / 10000.0);
1133  return sizeof(TDS_REAL);
1134  break;
1135  case SYBMONEY:
1136  cr->m.mny = (TDS_INT8) mny.mny4;
1137  return sizeof(TDS_MONEY);
1138  break;
1139  case SYBMONEY4:
1140  cr->m4 = mny;
1141  return sizeof(TDS_MONEY4);
1142  break;
1143  case SYBDECIMAL:
1144  case SYBNUMERIC:
1145  if (mny.mny4 < 0)
1146  return tds_convert_int_numeric(4, 1, (TDS_UINT) -mny.mny4, cr);
1147  return tds_convert_int_numeric(4, 0, (TDS_UINT) mny.mny4, cr);
1148  /* conversions not allowed */
1149  case SYBUNIQUE:
1150  case SYBDATETIME4:
1151  case SYBDATETIME:
1152  case SYBDATETIMN:
1153  default:
1154  return TDS_CONVERT_NOAVAIL;
1155  break;
1156  }
1157  return TDS_CONVERT_FAIL;
1158 }
1159 
1160 static TDS_INT
1161 tds_convert_money(const TDS_MONEY * src, int desttype, CONV_RESULT * cr)
1162 {
1163  char *s;
1164 
1165  TDS_INT8 mymoney, dollars;
1166  char tmpstr[64];
1167 
1168  tdsdump_log(TDS_DBG_FUNC, "tds_convert_money()\n");
1169  mymoney = ((TDS_INT8) src->tdsoldmoney.mnyhigh << 32) | src->tdsoldmoney.mnylow;
1170 
1171  switch (desttype) {
1172  case TDS_CONVERT_CHAR:
1173  case CASE_ALL_CHAR:
1174  s = tds_money_to_string((const TDS_MONEY *) src, tmpstr);
1175  return string_to_result(s, cr);
1176  break;
1177  case SYBINT1:
1178  case SYBUINT1:
1179  if (mymoney <= -10000 || mymoney >= 256 * 10000)
1180  return TDS_CONVERT_OVERFLOW;
1181  /* TODO: round ?? */
1182  cr->ti = (TDS_TINYINT) (((TDS_INT) mymoney) / 10000);
1183  return sizeof(TDS_TINYINT);
1184  break;
1185  case SYBINT2:
1186  if (mymoney <= -32769 * 10000 || mymoney >= 32768 * 10000)
1187  return TDS_CONVERT_OVERFLOW;
1188  cr->si = (TDS_SMALLINT) (((TDS_INT) mymoney) / 10000);
1189  return sizeof(TDS_SMALLINT);
1190  break;
1191  case SYBUINT2:
1192  if (mymoney <= -1 * 10000 || mymoney >= 65536 * 10000)
1193  return TDS_CONVERT_OVERFLOW;
1194  cr->usi = (TDS_USMALLINT) (((TDS_INT) mymoney) / 10000);
1195  return sizeof(TDS_USMALLINT);
1196  break;
1197  case SYBINT4:
1198  dollars = mymoney / 10000;
1199  if (!IS_INT(dollars))
1200  return TDS_CONVERT_OVERFLOW;
1201  cr->i = (TDS_INT) dollars;
1202  return sizeof(TDS_INT);
1203  break;
1204  case SYBUINT4:
1205  dollars = mymoney / 10000;
1206  if (!IS_UINT(dollars))
1207  return TDS_CONVERT_OVERFLOW;
1208  cr->ui = (TDS_UINT) dollars;
1209  return sizeof(TDS_UINT);
1210  break;
1211  case SYBINT8:
1212  cr->bi = mymoney / 10000;
1213  return sizeof(TDS_INT8);
1214  break;
1215  case SYBUINT8:
1216  dollars = mymoney / 10000;
1217  if (dollars < 0)
1218  return TDS_CONVERT_OVERFLOW;
1219  cr->ubi = (TDS_UINT8) dollars;
1220  return sizeof(TDS_UINT8);
1221  break;
1222  case SYBBIT:
1223  case SYBBITN:
1224  cr->ti = mymoney ? 1 : 0;
1225  return sizeof(TDS_TINYINT);
1226  break;
1227  case SYBFLT8:
1228  cr->f = ((TDS_FLOAT) mymoney) / 10000.0;
1229  return sizeof(TDS_FLOAT);
1230  break;
1231  case SYBREAL:
1232  cr->r = (TDS_REAL) (mymoney / 10000.0);
1233  return sizeof(TDS_REAL);
1234  break;
1235  case SYBMONEY4:
1236  if (!IS_INT(mymoney))
1237  return TDS_CONVERT_OVERFLOW;
1238  cr->m4.mny4 = (TDS_INT) mymoney;
1239  return sizeof(TDS_MONEY4);
1240  break;
1241  case SYBMONEY:
1242  cr->m.mny = mymoney;
1243  return sizeof(TDS_MONEY);
1244  break;
1245  case SYBDECIMAL:
1246  case SYBNUMERIC:
1247  if (mymoney < 0)
1248  return tds_convert_int8_numeric(4, 1, -mymoney, cr);
1249  return tds_convert_int8_numeric(4, 0, mymoney, cr);
1250  break;
1251  /* conversions not allowed */
1252  case SYBUNIQUE:
1253  case SYBDATETIME4:
1254  case SYBDATETIME:
1255  case SYBDATETIMN:
1256  default:
1257  break;
1258  }
1259  return TDS_CONVERT_NOAVAIL;
1260 }
1261 
1262 static TDS_INT
1263 tds_convert_datetimeall(const TDSCONTEXT * tds_ctx, int srctype, const TDS_DATETIMEALL * dta, int desttype, CONV_RESULT * cr)
1264 {
1265  char whole_date_string[64];
1266  TDSDATEREC when;
1267 
1268  switch (desttype) {
1269  case TDS_CONVERT_CHAR:
1270  case CASE_ALL_CHAR:
1271  tds_datecrack(srctype, dta, &when);
1272  tds_strftime(whole_date_string, sizeof(whole_date_string), tds_ctx->locale->date_fmt, &when,
1273  dta->time_prec);
1274 
1275  return string_to_result(whole_date_string, cr);
1276  case SYBDATETIME:
1277  if (!IS_INT(dta->date))
1278  return TDS_CONVERT_OVERFLOW;
1279  cr->dt.dtdays = (TDS_INT) dta->date;
1280  cr->dt.dttime = (TDS_INT) ((dta->time * 3u + 50000u) / 100000u);
1281  return sizeof(TDS_DATETIME);
1282  case SYBDATETIME4:
1283  if (!IS_USMALLINT(dta->date))
1284  return TDS_CONVERT_OVERFLOW;
1285  cr->dt4.days = (TDS_USMALLINT) dta->date;
1286  cr->dt4.minutes = (TDS_USMALLINT) ((dta->time + 30u * 10000000u) / (60u * 10000000u));
1287  return sizeof(TDS_DATETIME4);
1288  case SYBMSDATETIMEOFFSET:
1289  case SYBMSDATE:
1290  case SYBMSTIME:
1291  case SYBMSDATETIME2:
1292  cr->dta = *dta;
1293  return sizeof(TDS_DATETIMEALL);
1294  case SYBDATE:
1295  if (!IS_INT(dta->date))
1296  return TDS_CONVERT_OVERFLOW;
1297  cr->date = (TDS_INT) dta->date;
1298  return sizeof(TDS_DATE);
1299  case SYBTIME:
1300  cr->time = (TDS_INT) ((dta->time * 3u + 50000u) / 100000u);
1301  return sizeof(TDS_TIME);
1302  case SYB5BIGTIME:
1303  cr->bigtime = dta->time / 10u;
1304  return sizeof(TDS_UINT8);
1305  case SYB5BIGDATETIME:
1306  cr->bigtime = dta->time / 10u
1307  + (dta->date + BIGDATETIME_BIAS) * ((TDS_UINT8) 86400u * 1000000u);
1308  return sizeof(TDS_UINT8);
1309  /* conversions not allowed */
1310  case SYBUNIQUE:
1311  case SYBBIT:
1312  case SYBBITN:
1313  case SYBINT1:
1314  case SYBUINT1:
1315  case SYBINT2:
1316  case SYBUINT2:
1317  case SYBINT4:
1318  case SYBUINT4:
1319  case SYBINT8:
1320  case SYBUINT8:
1321  case SYBMONEY4:
1322  case SYBMONEY:
1323  case SYBNUMERIC:
1324  case SYBDECIMAL:
1325  default:
1326  break;
1327  }
1328  return TDS_CONVERT_NOAVAIL;
1329 }
1330 
1331 static TDS_INT
1332 tds_convert_datetime(const TDSCONTEXT * tds_ctx, const TDS_DATETIME * dt, int desttype, unsigned precision, CONV_RESULT * cr)
1333 {
1334  char whole_date_string[64];
1335  TDSDATEREC when;
1336 
1337  switch (desttype) {
1338  case TDS_CONVERT_CHAR:
1339  case CASE_ALL_CHAR:
1340  tds_datecrack(SYBDATETIME, dt, &when);
1341  tds_strftime(whole_date_string, sizeof(whole_date_string), tds_ctx->locale->date_fmt, &when, 3);
1342 
1343  return string_to_result(whole_date_string, cr);
1344  case SYBDATETIME:
1345  cr->dt = *dt;
1346  return sizeof(TDS_DATETIME);
1347  case SYBDATETIME4:
1348  if (!IS_USMALLINT(dt->dtdays))
1349  return TDS_CONVERT_OVERFLOW;
1350  cr->dt4.days = dt->dtdays;
1351  cr->dt4.minutes = (dt->dttime / 300) / 60;
1352  return sizeof(TDS_DATETIME4);
1353  case SYBDATE:
1354  cr->date = dt->dtdays;
1355  return sizeof(TDS_DATE);
1356  case SYBTIME:
1357  cr->time = dt->dttime;
1358  return sizeof(TDS_TIME);
1359  case SYBMSDATETIMEOFFSET:
1360  case SYBMSDATE:
1361  case SYBMSTIME:
1362  case SYBMSDATETIME2:
1363  memset(&cr->dta, 0, sizeof(cr->dta));
1364  cr->dta.time_prec = precision;
1365  if (desttype == SYBMSDATETIMEOFFSET)
1366  cr->dta.has_offset = 1;
1367  if (desttype != SYBMSDATE) {
1368  cr->dta.has_time = 1;
1369  cr->dta.time_prec = 3;
1370  cr->dta.time = ((TDS_UINT8) dt->dttime) * 100000u / 3u;
1371  }
1372  if (desttype != SYBMSTIME) {
1373  cr->dta.has_date = 1;
1374  cr->dta.date = dt->dtdays;
1375  }
1376  return sizeof(TDS_DATETIMEALL);
1377  case SYB5BIGTIME:
1378  cr->bigtime = ((TDS_UINT8) dt->dttime) * 10000u / 3u;
1379  return sizeof(TDS_BIGTIME);
1380  case SYB5BIGDATETIME:
1381  cr->bigdatetime = ((TDS_UINT8) dt->dttime) * 10000u / 3u
1382  + (dt->dtdays + BIGDATETIME_BIAS) * ((TDS_UINT8) 86400u * 1000000u);
1383  return sizeof(TDS_BIGDATETIME);
1384  /* conversions not allowed */
1385  case SYBUNIQUE:
1386  case SYBBIT:
1387  case SYBBITN:
1388  case SYBINT1:
1389  case SYBUINT1:
1390  case SYBINT2:
1391  case SYBUINT2:
1392  case SYBINT4:
1393  case SYBUINT4:
1394  case SYBINT8:
1395  case SYBUINT8:
1396  case SYBMONEY4:
1397  case SYBMONEY:
1398  case SYBNUMERIC:
1399  case SYBDECIMAL:
1400  default:
1401  break;
1402  }
1403  return TDS_CONVERT_NOAVAIL;
1404 }
1405 
1406 static TDS_INT
1407 tds_convert_datetime4(const TDSCONTEXT * tds_ctx, const TDS_DATETIME4 * dt4, int desttype, CONV_RESULT * cr)
1408 {
1409  TDS_DATETIME dt;
1410 
1411  if (desttype == SYBDATETIME4) {
1412  cr->dt4 = *dt4;
1413  return sizeof(TDS_DATETIME4);
1414  }
1415 
1416  /* convert to DATETIME and use tds_convert_datetime */
1417  dt.dtdays = dt4->days;
1418  dt.dttime = dt4->minutes * (60u * 300u);
1419  return tds_convert_datetime(tds_ctx, &dt, desttype, 0, cr);
1420 }
1421 
1422 static TDS_INT
1423 tds_convert_time(const TDSCONTEXT * tds_ctx, const TDS_TIME * time, int desttype, CONV_RESULT * cr)
1424 {
1425  TDS_DATETIME dt;
1426 
1427  if (desttype == SYBTIME) {
1428  cr->time = *time;
1429  return sizeof(TDS_TIME);
1430  }
1431 
1432  /* convert to DATETIME and use tds_convert_datetime */
1433  dt.dtdays = 0;
1434  dt.dttime = *time;
1435  return tds_convert_datetime(tds_ctx, &dt, desttype, 0, cr);
1436 }
1437 
1438 static TDS_INT
1439 tds_convert_date(const TDSCONTEXT * tds_ctx, const TDS_DATE * date, int desttype, CONV_RESULT * cr)
1440 {
1441  TDS_DATETIME dt;
1442 
1443  if (desttype == SYBDATE) {
1444  cr->date = *date;
1445  return sizeof(TDS_DATE);
1446  }
1447 
1448  /* convert to DATETIME and use tds_convert_datetime */
1449  dt.dtdays = *date;
1450  dt.dttime = 0;
1451  return tds_convert_datetime(tds_ctx, &dt, desttype, 0, cr);
1452 }
1453 
1454 static TDS_INT
1455 tds_convert_bigtime(const TDSCONTEXT * tds_ctx, const TDS_BIGTIME * bigtime, int desttype, CONV_RESULT * cr)
1456 {
1457  TDS_DATETIMEALL dta;
1458 
1459  if (desttype == SYB5BIGTIME) {
1460  cr->bigtime = *bigtime;
1461  return sizeof(TDS_BIGTIME);
1462  }
1463 
1464  /* convert to DATETIMEALL and use tds_convert_datetimeall */
1465  memset(&dta, 0, sizeof(dta));
1466  dta.time_prec = 6;
1467  dta.has_time = 1;
1468  dta.time = *bigtime % ((TDS_UINT8) 86400u * 1000000u) * 10u;
1469  return tds_convert_datetimeall(tds_ctx, SYBMSTIME, &dta, desttype, cr);
1470 }
1471 
1472 static TDS_INT
1473 tds_convert_bigdatetime(const TDSCONTEXT * tds_ctx, const TDS_BIGDATETIME * bigdatetime, int desttype, CONV_RESULT * cr)
1474 {
1475  TDS_DATETIMEALL dta;
1476  TDS_UINT8 bdt;
1477 
1478  if (desttype == SYB5BIGDATETIME) {
1479  cr->bigdatetime = *bigdatetime;
1480  return sizeof(TDS_BIGDATETIME);
1481  }
1482 
1483  /* convert to DATETIMEALL and use tds_convert_datetimeall */
1484  bdt = *bigdatetime;
1485  memset(&dta, 0, sizeof(dta));
1486  dta.time_prec = 6;
1487  dta.has_time = 1;
1488  dta.time = bdt % ((TDS_UINT8) 86400u * 1000000u) * 10u;
1489  bdt /= (TDS_UINT8) 86400u * 1000000u;
1490  dta.has_date = 1;
1491  dta.date = (TDS_INT) (bdt - BIGDATETIME_BIAS);
1492  return tds_convert_datetimeall(tds_ctx, SYBMSDATETIME2, &dta, desttype, cr);
1493 }
1494 
1495 
1496 static TDS_INT
1497 tds_convert_real(const TDS_REAL* src, int desttype, CONV_RESULT * cr)
1498 {
1499  TDS_REAL the_value;
1500 
1501 /* FIXME how many big should be this buffer ?? */
1502  char tmp_str[128];
1503  TDS_INT mymoney4;
1504  TDS_INT8 mymoney;
1505 
1506  the_value = *src;
1507 
1508  switch (desttype) {
1509  case TDS_CONVERT_CHAR:
1510  case CASE_ALL_CHAR:
1511  sprintf(tmp_str, "%.9g", the_value);
1512  return string_to_result(tmp_str, cr);
1513  break;
1514  case SYBINT1:
1515  case SYBUINT1:
1516  if (!IS_TINYINT(the_value))
1517  return TDS_CONVERT_OVERFLOW;
1518  cr->ti = (TDS_TINYINT) the_value;
1519  return sizeof(TDS_TINYINT);
1520  break;
1521  case SYBINT2:
1522  if (!IS_SMALLINT(the_value))
1523  return TDS_CONVERT_OVERFLOW;
1524  cr->si = (TDS_SMALLINT) the_value;
1525  return sizeof(TDS_SMALLINT);
1526  break;
1527  case SYBUINT2:
1528  if (!IS_USMALLINT(the_value))
1529  return TDS_CONVERT_OVERFLOW;
1530  cr->usi = (TDS_USMALLINT) the_value;
1531  return sizeof(TDS_USMALLINT);
1532  break;
1533  case SYBINT4:
1534  if (!IS_INT((double)the_value))
1535  return TDS_CONVERT_OVERFLOW;
1536  cr->i = (TDS_INT) the_value;
1537  return sizeof(TDS_INT);
1538  break;
1539  case SYBUINT4:
1540  if (!IS_UINT((double)the_value))
1541  return TDS_CONVERT_OVERFLOW;
1542  cr->ui = (TDS_UINT) the_value;
1543  return sizeof(TDS_UINT);
1544  break;
1545  case SYBINT8:
1546  if (the_value > (TDS_REAL) TDS_INT8_MAX || the_value < (TDS_REAL) TDS_INT8_MIN)
1547  return TDS_CONVERT_OVERFLOW;
1548  cr->bi = (TDS_INT8) the_value;
1549  return sizeof(TDS_INT8);
1550  break;
1551  case SYBUINT8:
1552  if (the_value > (TDS_REAL) TDS_UINT8_MAX || the_value < 0)
1553  return TDS_CONVERT_OVERFLOW;
1554  cr->ubi = (TDS_UINT8) the_value;
1555  return sizeof(TDS_UINT8);
1556  break;
1557  case SYBBIT:
1558  case SYBBITN:
1559  cr->ti = the_value ? 1 : 0;
1560  return sizeof(TDS_TINYINT);
1561  break;
1562 
1563  case SYBFLT8:
1564  cr->f = the_value;
1565  return sizeof(TDS_FLOAT);
1566  break;
1567 
1568  case SYBREAL:
1569  cr->r = the_value;
1570  return sizeof(TDS_REAL);
1571  break;
1572 
1573  case SYBMONEY:
1574  if (the_value > (TDS_REAL) (TDS_INT8_MAX / 10000) || the_value < (TDS_REAL) (TDS_INT8_MIN / 10000))
1575  return TDS_CONVERT_OVERFLOW;
1576  mymoney = (TDS_INT8) (the_value * 10000);
1577  cr->m.mny = mymoney;
1578  return sizeof(TDS_MONEY);
1579  break;
1580 
1581  case SYBMONEY4:
1582  if (the_value > (TDS_REAL) (TDS_INT_MAX / 10000) || the_value < (TDS_REAL) (TDS_INT_MIN / 10000))
1583  return TDS_CONVERT_OVERFLOW;
1584  mymoney4 = (TDS_INT) (the_value * 10000);
1585  cr->m4.mny4 = mymoney4;
1586  return sizeof(TDS_MONEY4);
1587  break;
1588  case SYBNUMERIC:
1589  case SYBDECIMAL:
1590  sprintf(tmp_str, "%.*f", cr->n.scale, the_value);
1591  return stringz_to_numeric(tmp_str, cr);
1592  break;
1593  /* not allowed */
1594  case SYBUNIQUE:
1595  case SYBDATETIME4:
1596  case SYBDATETIME:
1597  case SYBDATETIMN:
1598  default:
1599  break;
1600  }
1601  return TDS_CONVERT_NOAVAIL;
1602 }
1603 
1604 /*
1605  * TODO: emit SYBECLPR errors: "Data conversion resulted in loss of precision".
1606  * There are many places where this would be correct to do, but the test is tedious
1607  * (convert e.g. 1.5 -> SYBINT and test if output == input) and we don't have a good,
1608  * API-independent alternative to tds_client_msg(). Postponed until then.
1609  */
1610 static TDS_INT
1611 tds_convert_flt8(const TDS_FLOAT* src, int desttype, CONV_RESULT * cr)
1612 {
1613  TDS_FLOAT the_value;
1614  char tmp_str[25];
1615 
1616  memcpy(&the_value, src, 8);
1617  switch (desttype) {
1618  case TDS_CONVERT_CHAR:
1619  case CASE_ALL_CHAR:
1620  sprintf(tmp_str, "%.17g", the_value);
1621  return string_to_result(tmp_str, cr);
1622  break;
1623  case SYBINT1:
1624  case SYBUINT1:
1625  if (!IS_TINYINT(the_value))
1626  return TDS_CONVERT_OVERFLOW;
1627  cr->ti = (TDS_TINYINT) the_value;
1628  return sizeof(TDS_TINYINT);
1629  break;
1630  case SYBINT2:
1631  if (!IS_SMALLINT(the_value))
1632  return TDS_CONVERT_OVERFLOW;
1633  cr->si = (TDS_SMALLINT) the_value;
1634  return sizeof(TDS_SMALLINT);
1635  break;
1636  case SYBUINT2:
1637  if (!IS_USMALLINT(the_value))
1638  return TDS_CONVERT_OVERFLOW;
1639  cr->usi = (TDS_USMALLINT) the_value;
1640  return sizeof(TDS_USMALLINT);
1641  break;
1642  case SYBINT4:
1643  if (!IS_INT(the_value))
1644  return TDS_CONVERT_OVERFLOW;
1645  cr->i = (TDS_INT) the_value;
1646  return sizeof(TDS_INT);
1647  break;
1648  case SYBUINT4:
1649  if (!IS_UINT(the_value))
1650  return TDS_CONVERT_OVERFLOW;
1651  cr->ui = (TDS_UINT) the_value;
1652  return sizeof(TDS_UINT);
1653  break;
1654  case SYBINT8:
1655  if (the_value > (TDS_FLOAT) TDS_INT8_MAX || the_value < (TDS_FLOAT) TDS_INT8_MIN)
1656  return TDS_CONVERT_OVERFLOW;
1657  cr->bi = (TDS_INT8) the_value;
1658  return sizeof(TDS_INT8);
1659  break;
1660  case SYBUINT8:
1661  if (the_value > (TDS_FLOAT) TDS_UINT8_MAX || the_value < 0)
1662  return TDS_CONVERT_OVERFLOW;
1663  cr->ubi = (TDS_UINT8) the_value;
1664  return sizeof(TDS_UINT8);
1665  break;
1666  case SYBBIT:
1667  case SYBBITN:
1668  cr->ti = the_value ? 1 : 0;
1669  return sizeof(TDS_TINYINT);
1670  break;
1671 
1672  case SYBMONEY:
1673  if (the_value > (TDS_FLOAT) (TDS_INT8_MAX / 10000) || the_value < (TDS_FLOAT) (TDS_INT8_MIN / 10000))
1674  return TDS_CONVERT_OVERFLOW;
1675  cr->m.mny = (TDS_INT8) (the_value * 10000);
1676 
1677  return sizeof(TDS_MONEY);
1678  break;
1679  case SYBMONEY4:
1680  if (the_value > (TDS_FLOAT) (TDS_INT_MAX / 10000) || the_value < (TDS_FLOAT) (TDS_INT_MIN / 10000))
1681  return TDS_CONVERT_OVERFLOW;
1682  cr->m4.mny4 = (TDS_INT) (the_value * 10000);
1683  return sizeof(TDS_MONEY4);
1684  break;
1685  case SYBREAL:
1686  /* TODO check overflow */
1687  cr->r = (TDS_REAL)the_value;
1688  return sizeof(TDS_REAL);
1689  break;
1690  case SYBFLT8:
1691  cr->f = the_value;
1692  return sizeof(TDS_FLOAT);
1693  break;
1694  case SYBNUMERIC:
1695  case SYBDECIMAL:
1696  sprintf(tmp_str, "%.16g", the_value);
1697  return stringz_to_numeric(tmp_str, cr);
1698  break;
1699  /* not allowed */
1700  case SYBUNIQUE:
1701  case SYBDATETIME4:
1702  case SYBDATETIME:
1703  case SYBDATETIMN:
1704  default:
1705  break;
1706  }
1707  return TDS_CONVERT_NOAVAIL;
1708 }
1709 
1710 static TDS_INT
1711 tds_convert_unique(const TDS_CHAR * src, int desttype, CONV_RESULT * cr)
1712 {
1713  /*
1714  * raw data is equivalent to structure and always aligned,
1715  * so this cast is portable
1716  */
1717  const TDS_UNIQUE *u = (const TDS_UNIQUE *) src;
1718  char buf[37];
1719 
1720  switch (desttype) {
1721  case TDS_CONVERT_CHAR:
1722  case CASE_ALL_CHAR:
1723  sprintf(buf, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1724  (int) u->Data1, (int) u->Data2, (int) u->Data3,
1725  u->Data4[0], u->Data4[1], u->Data4[2], u->Data4[3], u->Data4[4], u->Data4[5], u->Data4[6], u->Data4[7]);
1726  return string_to_result(buf, cr);
1727  break;
1728  case SYBUNIQUE:
1729  /*
1730  * Here we can copy raw to structure because we adjust
1731  * byte order in tds_swap_datatype
1732  */
1733  memcpy(&(cr->u), src, sizeof(TDS_UNIQUE));
1734  return sizeof(TDS_UNIQUE);
1735  break;
1736  /* no not warning for not convertible types */
1737  case SYBBIT:
1738  case SYBBITN:
1739  case SYBINT1:
1740  case SYBUINT1:
1741  case SYBINT2:
1742  case SYBUINT2:
1743  case SYBINT4:
1744  case SYBUINT4:
1745  case SYBINT8:
1746  case SYBUINT8:
1747  case SYBMONEY4:
1748  case SYBMONEY:
1749  case SYBDATETIME4:
1750  case SYBDATETIME:
1751  case SYBDATETIMN:
1752  case SYBREAL:
1753  case SYBFLT8:
1754  default:
1755  break;
1756  }
1757  return TDS_CONVERT_NOAVAIL;
1758 }
1759 
1760 static TDS_INT
1761 tds_convert_to_binary(int srctype, const TDS_CHAR * src, TDS_UINT srclen, int desttype, CONV_RESULT * cr)
1762 {
1763  size_t len;
1764  TDS_CHAR *ib;
1765 
1766  switch (srctype) {
1767  case CASE_ALL_BINARY:
1768  len = srclen;
1769  break;
1770  case SYBBIT:
1771  case SYBBITN:
1772  case SYBINT1:
1773  case SYBUINT1:
1774  len = 1;
1775  break;
1776  case SYBINT2:
1777  case SYBUINT2:
1778  len = 2;
1779  break;
1780  case SYBINT4:
1781  case SYBUINT4:
1782  len = 4;
1783  break;
1784  case SYBINT8:
1785  case SYBUINT8:
1786  len = sizeof(TDS_INT8);
1787  break;
1788  case SYBMONEY4:
1789  len = sizeof(TDS_MONEY4);
1790  break;
1791  case SYBMONEY:
1792  len = sizeof(TDS_MONEY);
1793  break;
1794  case SYBNUMERIC:
1795  case SYBDECIMAL:
1796  len = sizeof(TDS_NUMERIC);
1797  break;
1798  case SYBREAL:
1799  len = sizeof(TDS_REAL);
1800  break;
1801  case SYBFLT8:
1802  len = sizeof(TDS_FLOAT);
1803  break;
1804  case SYBDATETIME:
1805  len = sizeof(TDS_DATETIME);
1806  break;
1807  case SYBDATETIME4:
1808  len = sizeof(TDS_DATETIME4);
1809  break;
1810  case SYBTIME:
1811  len = sizeof(TDS_TIME);
1812  break;
1813  case SYBDATE:
1814  len = sizeof(TDS_DATE);
1815  break;
1816  case SYBMSTIME:
1817  case SYBMSDATE:
1818  case SYBMSDATETIME2:
1819  case SYBMSDATETIMEOFFSET:
1820  len = sizeof(TDS_DATETIMEALL);
1821  break;
1822  case SYB5BIGTIME:
1823  len = sizeof(TDS_BIGTIME);
1824  break;
1825  case SYB5BIGDATETIME:
1826  len = sizeof(TDS_BIGDATETIME);
1827  break;
1828  case SYBUNIQUE:
1829  len = sizeof(TDS_UNIQUE);
1830  break;
1831  case CASE_ALL_CHAR:
1832 
1833  /* skip leading "0x" or "0X" */
1834  if (srclen >= 2 && src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) {
1835  src += 2;
1836  srclen -= 2;
1837  }
1838 
1839  /* ignore trailing blanks and nulls */
1840  /* FIXME is good to ignore null ?? */
1841  while (srclen > 0 && (src[srclen - 1] == ' ' || src[srclen - 1] == '\0'))
1842  --srclen;
1843 
1844  /* a binary string output will be half the length of */
1845  /* the string which represents it in hexadecimal */
1846 
1847  ib = cr->cb.ib;
1848  if (desttype != TDS_CONVERT_BINARY) {
1849  cr->ib = tds_new(TDS_CHAR, (srclen + 2u) / 2u);
1850  test_alloc(cr->ib);
1851  ib = cr->ib;
1852  }
1853  return (TDS_INT) tds_char2hex(ib,
1854  desttype == TDS_CONVERT_BINARY
1855  ? cr->cb.len : 0xffffffffu,
1856  src, srclen);
1857 
1858  default:
1859  return TDS_CONVERT_NOAVAIL;
1860  }
1861  return binary_to_result(desttype, src, len, cr);
1862 }
1863 
1864 /**
1865  * tds_convert
1866  * convert a type to another.
1867  * If you convert to SYBDECIMAL/SYBNUMERIC you MUST initialize precision
1868  * and scale of cr.
1869  * Do not expect strings to be zero terminated. Databases support zero inside
1870  * string. Using strlen may result on data loss or even a segmentation fault.
1871  * Instead, use memcpy to copy destination using length returned.
1872  * This function does not handle NULL, srclen should be >0. Client libraries handle NULLs each in their own way.
1873  * @param tds_ctx context (used in conversion to data and to return messages)
1874  * @param srctype type of source
1875  * @param src pointer to source data to convert
1876  * @param srclen length in bytes of source (not counting terminator or strings)
1877  * @param desttype type of destination
1878  * @param cr structure to hold result
1879  * @return length of result or TDS_CONVERT_* failure code on failure. All TDS_CONVERT_* constants are <0.
1880  */
1881 TDS_INT
1882 tds_convert(const TDSCONTEXT * tds_ctx, int srctype, const TDS_CHAR * src, TDS_UINT srclen, int desttype, CONV_RESULT * cr)
1883 {
1884  TDS_INT length = 0;
1885 
1886  assert(srclen >= 0 && srclen <= 2147483647u);
1887 
1888  if (srctype == SYBVARIANT) {
1889  TDSVARIANT *v = (TDSVARIANT*) src;
1890  srctype = v->type;
1891  src = v->data;
1892  srclen = v->data_len;
1893  }
1894 
1895  switch (desttype) {
1896  case CASE_ALL_BINARY:
1897  return tds_convert_to_binary(srctype, src, srclen, desttype, cr);
1898  }
1899 
1900  switch (srctype) {
1901  case CASE_ALL_CHAR:
1902  length = tds_convert_char(src, srclen, desttype, cr);
1903  break;
1904  case SYBMONEY4:
1905  length = tds_convert_money4((const TDS_MONEY4 *) src, desttype, cr);
1906  break;
1907  case SYBMONEY:
1908  length = tds_convert_money((const TDS_MONEY *) src, desttype, cr);
1909  break;
1910  case SYBNUMERIC:
1911  case SYBDECIMAL:
1912  length = tds_convert_numeric((const TDS_NUMERIC *) src, desttype, cr);
1913  break;
1914  case SYBBIT:
1915  case SYBBITN:
1916  length = tds_convert_bit(src, desttype, cr);
1917  break;
1918  case SYBINT1:
1919  case SYBUINT1:
1920  length = tds_convert_int1((const TDS_TINYINT *) src, desttype, cr);
1921  break;
1922  case SYBINT2:
1923  length = tds_convert_int2((const TDS_SMALLINT *) src, desttype, cr);
1924  break;
1925  case SYBUINT2:
1926  length = tds_convert_uint2((const TDS_USMALLINT *) src, desttype, cr);
1927  break;
1928  case SYBINT4:
1929  length = tds_convert_int4((const TDS_INT *) src, desttype, cr);
1930  break;
1931  case SYBUINT4:
1932  length = tds_convert_uint4((const TDS_UINT *) src, desttype, cr);
1933  break;
1934  case SYBINT8:
1935  length = tds_convert_int8((const TDS_INT8 *) src, desttype, cr);
1936  break;
1937  case SYBUINT8:
1938  length = tds_convert_uint8((const TDS_UINT8 *) src, desttype, cr);
1939  break;
1940  case SYBREAL:
1941  length = tds_convert_real((const TDS_REAL *) src, desttype, cr);
1942  break;
1943  case SYBFLT8:
1944  length = tds_convert_flt8((const TDS_FLOAT *) src, desttype, cr);
1945  break;
1946  case SYBMSTIME:
1947  case SYBMSDATE:
1948  case SYBMSDATETIME2:
1949  case SYBMSDATETIMEOFFSET:
1950  length = tds_convert_datetimeall(tds_ctx, srctype, (const TDS_DATETIMEALL *) src, desttype, cr);
1951  break;
1952  case SYBDATETIME:
1953  length = tds_convert_datetime(tds_ctx, (const TDS_DATETIME* ) src, desttype, 3, cr);
1954  break;
1955  case SYBDATETIME4:
1956  length = tds_convert_datetime4(tds_ctx, (const TDS_DATETIME4* ) src, desttype, cr);
1957  break;
1958  case SYBTIME:
1959  length = tds_convert_time(tds_ctx, (const TDS_TIME *) src, desttype, cr);
1960  break;
1961  case SYBDATE:
1962  length = tds_convert_date(tds_ctx, (const TDS_DATE *) src, desttype, cr);
1963  break;
1964  case SYB5BIGTIME:
1965  length = tds_convert_bigtime(tds_ctx, (const TDS_BIGTIME *) src, desttype, cr);
1966  break;
1967  case SYB5BIGDATETIME:
1968  length = tds_convert_bigdatetime(tds_ctx, (const TDS_BIGDATETIME *) src, desttype, cr);
1969  break;
1970  case CASE_ALL_BINARY:
1971  length = tds_convert_binary((const TDS_UCHAR *) src, srclen, desttype, cr);
1972  break;
1973  case SYBUNIQUE:
1974  length = tds_convert_unique(src, desttype, cr);
1975  break;
1976  default:
1977  return TDS_CONVERT_NOAVAIL;
1978  break;
1979  }
1980 
1981 /* fix MONEY case */
1982 #if !defined(WORDS_BIGENDIAN)
1983  if (length > 0 && desttype == SYBMONEY) {
1984  cr->m.mny = ((TDS_UINT8) cr->m.mny) >> 32 | (cr->m.mny << 32);
1985  }
1986 #endif
1987  return length;
1988 }
1989 
1990 static int
1991 string_to_datetime(const char *instr, TDS_UINT len, int desttype, CONV_RESULT * cr)
1992 {
1993  enum states
1994  { GOING_IN_BLIND,
1995  PUT_NUMERIC_IN_CONTEXT,
1996  DOING_ALPHABETIC_DATE,
1997  STRING_GARBLED
1998  };
1999 
2000  char *in;
2001  char *tok;
2002  char *lasts;
2003  char last_token[32];
2004  int monthdone = 0;
2005  int yeardone = 0;
2006  int mdaydone = 0;
2007 
2008  struct tds_time t;
2009 
2010  unsigned int dt_time;
2011  TDS_INT dt_days;
2012  int i;
2013 
2014  int current_state;
2015 
2016  memset(&t, '\0', sizeof(t));
2017  t.tm_mday = 1;
2018 
2019  in = tds_strndup(instr, len);
2020  test_alloc(in);
2021 
2022  tok = strtok_r(in, " ,", &lasts);
2023 
2024  current_state = GOING_IN_BLIND;
2025 
2026  while (tok != NULL) {
2027 
2028  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: current_state = %d\n", current_state);
2029  switch (current_state) {
2030  case GOING_IN_BLIND:
2031  /* If we have no idea of current context, then if we have */
2032  /* encountered a purely alphabetic string, it MUST be an */
2033  /* alphabetic month name or prefix... */
2034 
2035  if (is_alphabetic(tok)) {
2036  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_alphabetic\n");
2037  if (store_monthname(tok, &t) >= 0) {
2038  monthdone++;
2039  current_state = DOING_ALPHABETIC_DATE;
2040  } else {
2041  current_state = STRING_GARBLED;
2042  }
2043  }
2044 
2045  /* ...whereas if it is numeric, it could be a number of */
2046  /* things... */
2047 
2048  else if (is_numeric(tok)) {
2049  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_numeric\n");
2050  switch (strlen(tok)) {
2051  /* in this context a 4 character numeric can */
2052  /* ONLY be the year part of an alphabetic date */
2053 
2054  case 4:
2055  store_year(atoi(tok), &t);
2056  yeardone++;
2057  current_state = DOING_ALPHABETIC_DATE;
2058  break;
2059 
2060  /* whereas these could be the hour part of a */
2061  /* time specification ( 4 PM ) or the leading */
2062  /* day part of an alphabetic date ( 15 Jan ) */
2063 
2064  case 2:
2065  case 1:
2066  strcpy(last_token, tok);
2067  current_state = PUT_NUMERIC_IN_CONTEXT;
2068  break;
2069 
2070  /* this must be a [YY]YYMMDD date */
2071 
2072  case 6:
2073  case 8:
2074  if (store_yymmdd_date(tok, &t))
2075  current_state = GOING_IN_BLIND;
2076  else
2077  current_state = STRING_GARBLED;
2078  break;
2079 
2080  /* anything else is nonsense... */
2081 
2082  default:
2083  current_state = STRING_GARBLED;
2084  break;
2085  }
2086  }
2087 
2088  /* it could be [M]M/[D]D/[YY]YY format */
2089 
2090  else if (is_numeric_dateformat(tok)) {
2091  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_numeric_dateformat\n");
2092  store_numeric_date(tok, &t);
2093  current_state = GOING_IN_BLIND;
2094  } else if (is_dd_mon_yyyy(tok)) {
2095  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_dd_mon_yyyy\n");
2096  store_dd_mon_yyy_date(tok, &t);
2097  current_state = GOING_IN_BLIND;
2098  } else if (is_timeformat(tok)) {
2099  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: is_timeformat\n");
2100  store_time(tok, &t);
2101  current_state = GOING_IN_BLIND;
2102  } else {
2103  tdsdump_log(TDS_DBG_INFO1, "string_to_datetime: string_garbled\n");
2104  current_state = STRING_GARBLED;
2105  }
2106 
2107  break; /* end of GOING_IN_BLIND */
2108 
2109  case DOING_ALPHABETIC_DATE:
2110 
2111  if (is_alphabetic(tok)) {
2112  if (!monthdone && store_monthname(tok, &t) >= 0) {
2113  monthdone++;
2114  if (monthdone && yeardone && mdaydone)
2115  current_state = GOING_IN_BLIND;
2116  else
2117  current_state = DOING_ALPHABETIC_DATE;
2118  } else {
2119  current_state = STRING_GARBLED;
2120  }
2121  } else if (is_numeric(tok)) {
2122  if (mdaydone && yeardone)
2123  current_state = STRING_GARBLED;
2124  else
2125  switch (strlen(tok)) {
2126  case 4:
2127  store_year(atoi(tok), &t);
2128  yeardone++;
2129  if (monthdone && yeardone && mdaydone)
2130  current_state = GOING_IN_BLIND;
2131  else
2132  current_state = DOING_ALPHABETIC_DATE;
2133  break;
2134 
2135  case 2:
2136  case 1:
2137  if (!mdaydone) {
2138  store_mday(tok, &t);
2139 
2140  mdaydone++;
2141  if (monthdone && yeardone && mdaydone)
2142  current_state = GOING_IN_BLIND;
2143  else
2144  current_state = DOING_ALPHABETIC_DATE;
2145  } else {
2146  store_year(atoi(tok), &t);
2147  yeardone++;
2148  if (monthdone && yeardone && mdaydone)
2149  current_state = GOING_IN_BLIND;
2150  else
2151  current_state = DOING_ALPHABETIC_DATE;
2152  }
2153  break;
2154 
2155  default:
2156  current_state = STRING_GARBLED;
2157  }
2158  } else {
2159  current_state = STRING_GARBLED;
2160  }
2161 
2162  break; /* end of DOING_ALPHABETIC_DATE */
2163 
2164  case PUT_NUMERIC_IN_CONTEXT:
2165 
2166  if (is_alphabetic(tok)) {
2167  if (store_monthname(tok, &t) >= 0) {
2168  store_mday(last_token, &t);
2169  mdaydone++;
2170  monthdone++;
2171  if (monthdone && yeardone && mdaydone)
2172  current_state = GOING_IN_BLIND;
2173  else
2174  current_state = DOING_ALPHABETIC_DATE;
2175  } else if (is_ampm(tok)) {
2176  store_hour(last_token, tok, &t);
2177  current_state = GOING_IN_BLIND;
2178  } else {
2179  current_state = STRING_GARBLED;
2180  }
2181  } else if (is_numeric(tok)) {
2182  switch (strlen(tok)) {
2183  case 4:
2184  case 2:
2185  store_mday(last_token, &t);
2186  mdaydone++;
2187  store_year(atoi(tok), &t);
2188  yeardone++;
2189 
2190  if (monthdone && yeardone && mdaydone)
2191  current_state = GOING_IN_BLIND;
2192  else
2193  current_state = DOING_ALPHABETIC_DATE;
2194  break;
2195 
2196  default:
2197  current_state = STRING_GARBLED;
2198  }
2199  } else {
2200  current_state = STRING_GARBLED;
2201  }
2202 
2203  break; /* end of PUT_NUMERIC_IN_CONTEXT */
2204 
2205  case STRING_GARBLED:
2206 
2208  "error_handler: Attempt to convert data stopped by syntax error in source field \n");
2209  free(in);
2210  return TDS_CONVERT_SYNTAX;
2211  }
2212 
2213  tok = strtok_r(NULL, " ,", &lasts);
2214  }
2215 
2216  i = (t.tm_mon - 13) / 12;
2217  dt_days = 1461 * (t.tm_year + 1900 + i) / 4 +
2218  (367 * (t.tm_mon - 1 - 12 * i)) / 12 - (3 * ((t.tm_year + 2000 + i) / 100)) / 4 + t.tm_mday - 693932;
2219 
2220  free(in);
2221 
2222  if (desttype == SYBDATE) {
2223  cr->date = dt_days;
2224  return sizeof(TDS_DATE);
2225  }
2226  dt_time = t.tm_hour * 60 + t.tm_min;
2227  /* TODO check for overflow */
2228  if (desttype == SYBDATETIME4) {
2229  cr->dt4.days = dt_days;
2230  cr->dt4.minutes = dt_time;
2231  return sizeof(TDS_DATETIME4);
2232  }
2233  dt_time = dt_time * 60 + t.tm_sec;
2234  if (desttype == SYBDATETIME) {
2235  cr->dt.dtdays = dt_days;
2236  cr->dt.dttime = dt_time * 300 + (t.tm_ns / 1000000u * 300 + 150) / 1000;
2237  return sizeof(TDS_DATETIME);
2238  }
2239  if (desttype == SYBTIME) {
2240  cr->time = dt_time * 300 + (t.tm_ns / 1000000u * 300 + 150) / 1000;
2241  return sizeof(TDS_TIME);
2242  }
2243  if (desttype == SYB5BIGTIME) {
2244  cr->bigtime = dt_time * (TDS_UINT8) 1000000u + t.tm_ns / 1000u;
2245  return sizeof(TDS_BIGTIME);
2246  }
2247  if (desttype == SYB5BIGDATETIME) {
2248  cr->bigdatetime = (dt_days + BIGDATETIME_BIAS) * ((TDS_UINT8) 86400u * 1000000u)
2249  + dt_time * (TDS_UINT8) 1000000u + t.tm_ns / 1000u;
2250  return sizeof(TDS_BIGDATETIME);
2251  }
2252 
2253  cr->dta.has_offset = 0;
2254  cr->dta.offset = 0;
2255  cr->dta.has_date = 1;
2256  cr->dta.date = dt_days;
2257  cr->dta.has_time = 1;
2258  cr->dta.time_prec = 7; /* TODO correct value */
2259  cr->dta.time = ((TDS_UINT8) dt_time) * 10000000u + t.tm_ns / 100u;
2260  return sizeof(TDS_DATETIMEALL);
2261 }
2262 
2263 static int
2264 stringz_to_numeric(const char *instr, CONV_RESULT * cr)
2265 {
2266  return string_to_numeric(instr, instr + strlen(instr), cr);
2267 }
2268 
2269 static int
2270 string_to_numeric(const char *instr, const char *pend, CONV_RESULT * cr)
2271 {
2272  char mynumber[(MAXPRECISION + 7) / 8 * 8 + 8];
2273 
2274  /* num packaged 8 digit, see below for detail */
2275  TDS_UINT packed_num[(MAXPRECISION + 7) / 8];
2276 
2277  char *ptr;
2278 
2279  int i = 0;
2280  int j = 0;
2281  int bytes;
2282 
2283  bool negative;
2284  size_t digits, decimals;
2285 
2286  /* FIXME: application can pass invalid value for precision and scale ?? */
2287  if (cr->n.precision > MAXPRECISION)
2288  return TDS_CONVERT_FAIL;
2289 
2290  if (cr->n.precision == 0)
2291  cr->n.precision = MAXPRECISION; /* assume max precision */
2292 
2293  if (cr->n.scale > cr->n.precision)
2294  return TDS_CONVERT_FAIL;
2295 
2296  instr = parse_numeric(instr, pend, &negative, &digits, &decimals);
2297  if (!instr)
2298  return TDS_CONVERT_SYNTAX;
2299 
2300  cr->n.array[0] = negative ? 1 : 0;
2301 
2302  /* translate a number like 000ddddd.ffff to 00000000dddddffff00 */
2303 
2304  /*
2305  * Having disposed of any sign and leading blanks,
2306  * vet the digit string, counting places before and after
2307  * the decimal point. Dispense with trailing blanks, if any.
2308  */
2309 
2310  ptr = mynumber;
2311  for (i = 0; i < 8; ++i)
2312  *ptr++ = '0';
2313 
2314  /* too many digits, error */
2315  if (cr->n.precision - cr->n.scale < digits)
2316  return TDS_CONVERT_OVERFLOW;
2317 
2318  /* copy digits before the dot */
2319  memcpy(ptr, instr, digits);
2320  ptr += digits;
2321  instr += digits + 1;
2322 
2323  /* copy digits after the dot */
2324  if (decimals > cr->n.scale)
2325  decimals = cr->n.scale;
2326  memcpy(ptr, instr, decimals);
2327 
2328  /* fill up decimal digits */
2329  memset(ptr + decimals, '0', cr->n.scale - decimals);
2330  ptr += cr->n.scale;
2331 
2332  /*
2333  * Packaged number explanation:
2334  * We package 8 decimal digits in one number.
2335  * Because 10^8 = 5^8 * 2^8 = 5^8 * 256, dividing 10^8 by 256 leaves no remainder.
2336  * We can thus split it into bytes in an optimized way.
2337  */
2338 
2339  /* transform to packaged one */
2340  j = -1;
2341  ptr -= 8;
2342  do {
2343  TDS_UINT n = *ptr++;
2344 
2345  for (i = 1; i < 8; ++i)
2346  n = n * 10u + *ptr++;
2347  /* fix packet number and store */
2348  packed_num[++j] = n - ((TDS_UINT) '0' * 11111111lu);
2349  ptr -= 16;
2350  } while (ptr > mynumber);
2351 
2352  memset(cr->n.array + 1, 0, sizeof(cr->n.array) - 1);
2353  bytes = tds_numeric_bytes_per_prec[cr->n.precision];
2354  while (j > 0 && !packed_num[j])
2355  --j;
2356 
2357  for (;;) {
2358  bool is_zero = true;
2359  TDS_UINT carry = 0;
2360  i = j;
2361  if (!packed_num[j])
2362  --j;
2363  do {
2364  TDS_UINT tmp = packed_num[i];
2365  if (tmp)
2366  is_zero = false;
2367 
2368  /* divide for 256 for find another byte */
2369  /*
2370  * carry * (25u*25u*25u*25u) = carry * 10^8 / 256u
2371  * using unsigned number is just an optimization
2372  * compiler can translate division to a shift and remainder
2373  * to a binary AND
2374  */
2375  packed_num[i] = carry * (25u * 25u * 25u * 25u) + tmp / 256u;
2376  carry = tmp % 256u;
2377  } while(--i >= 0);
2378  if (is_zero)
2379  break;
2380  /*
2381  * source number is limited to 38 decimal digit
2382  * 10^39-1 < 2^128 (16 byte) so this cannot make an overflow
2383  */
2384  cr->n.array[--bytes] = carry;
2385  }
2386  return sizeof(TDS_NUMERIC);
2387 }
2388 
2389 static bool
2391 {
2392  const char *instr;
2393  int slashes = 0;
2394  int hyphens = 0;
2395  int periods = 0;
2396  int digits = 0;
2397 
2398  for (instr = t; *instr; instr++) {
2399  if (!isdigit((unsigned char) *instr) && *instr != '/' && *instr != '-' && *instr != '.')
2400  return false;
2401 
2402  if (*instr == '/')
2403  slashes++;
2404  else if (*instr == '-')
2405  hyphens++;
2406  else if (*instr == '.')
2407  periods++;
2408  else
2409  digits++;
2410 
2411  }
2412  if (hyphens + slashes + periods != 2)
2413  return false;
2414  if (hyphens == 1 || slashes == 1 || periods == 1)
2415  return false;
2416 
2417  if (digits < 4 || digits > 8)
2418  return false;
2419 
2420  return true;
2421 
2422 }
2423 
2424 /* This function will check if an alphanumeric string */
2425 /* holds a date in any of the following formats : */
2426 /* DD-MON-YYYY */
2427 /* DD-MON-YY */
2428 /* DDMONYY */
2429 /* DDMONYYYY */
2430 static bool
2432 {
2433  char *instr;
2434  char month[4];
2435 
2436  instr = t;
2437 
2438  if (!isdigit((unsigned char) *instr))
2439  return false;
2440 
2441  instr++;
2442 
2443  if (!isdigit((unsigned char) *instr))
2444  return false;
2445 
2446  instr++;
2447 
2448  if (*instr == '-') {
2449  instr++;
2450 
2451  strlcpy(month, instr, 4);
2452 
2453  if (!is_monthname(month))
2454  return false;
2455 
2456  instr += 3;
2457 
2458  if (*instr != '-')
2459  return false;
2460 
2461  instr++;
2462  if (!isdigit((unsigned char) *instr))
2463  return false;
2464 
2465  instr++;
2466  if (!isdigit((unsigned char) *instr))
2467  return false;
2468 
2469  instr++;
2470 
2471  if (*instr) {
2472  if (!isdigit((unsigned char) *instr))
2473  return false;
2474 
2475  instr++;
2476  if (!isdigit((unsigned char) *instr))
2477  return false;
2478  }
2479 
2480  } else {
2481 
2482  strlcpy(month, instr, 4);
2483 
2484  if (!is_monthname(month))
2485  return false;
2486 
2487  instr += 3;
2488 
2489  if (!isdigit((unsigned char) *instr))
2490  return false;
2491 
2492  instr++;
2493  if (!isdigit((unsigned char) *instr))
2494  return false;
2495 
2496  instr++;
2497  if (*instr) {
2498  if (!isdigit((unsigned char) *instr))
2499  return false;
2500 
2501  instr++;
2502  if (!isdigit((unsigned char) *instr))
2503  return false;
2504  }
2505  }
2506 
2507  return true;
2508 
2509 }
2510 
2511 static bool
2512 is_ampm(const char *datestr)
2513 {
2514  if (strcasecmp(datestr, "am") == 0)
2515  return true;
2516 
2517  if (strcasecmp(datestr, "pm") == 0)
2518  return true;
2519 
2520  return false;
2521 }
2522 
2523 static bool
2524 is_alphabetic(const char *datestr)
2525 {
2526  const char *s;
2527 
2528  for (s = datestr; *s; s++) {
2529  if (!isalpha((unsigned char) *s))
2530  return false;
2531  }
2532  return true;
2533 }
2534 
2535 static bool
2536 is_numeric(const char *datestr)
2537 {
2538  const char *s;
2539 
2540  for (s = datestr; *s; s++) {
2541  if (!isdigit((unsigned char) *s))
2542  return false;
2543  }
2544  return true;
2545 }
2546 
2547 static bool
2548 is_timeformat(const char *datestr)
2549 {
2550  const char *s;
2551 
2552  for (s = datestr; *s; s++) {
2553  if (!isdigit((unsigned char) *s) && *s != ':' && *s != '.')
2554  break;
2555  }
2556  if (*s)
2557  return is_ampm(s);
2558 
2559  return true;
2560 }
2561 
2562 static int
2563 store_year(int year, struct tds_time *t)
2564 {
2565 
2566  if (year < 0)
2567  return 0;
2568 
2569  if (year < 100) {
2570  if (year > 49)
2571  t->tm_year = year;
2572  else
2573  t->tm_year = 100 + year;
2574  return (1);
2575  }
2576 
2577  if (year < 1753)
2578  return (0);
2579 
2580  if (year <= 9999) {
2581  t->tm_year = year - 1900;
2582  return (1);
2583  }
2584 
2585  return (0);
2586 
2587 }
2588 
2589 static int
2590 store_mday(const char *datestr, struct tds_time *t)
2591 {
2592  int mday = atoi(datestr);
2593 
2594  if (mday > 0 && mday < 32) {
2595  t->tm_mday = mday;
2596  return 1;
2597  }
2598  return 0;
2599 }
2600 
2601 static int
2602 store_numeric_date(const char *datestr, struct tds_time *t)
2603 {
2604  int TDS_MONTH = 0;
2605  int TDS_DAY = 0;
2606  int TDS_YEAR = 0;
2607 
2608  int state;
2609  char last_char = 0;
2610  const char *s;
2611  int month = 0, year = 0, mday = 0;
2612 
2613  /* Its YYYY-MM-DD format */
2614 
2615  if (strlen(datestr) == 10 && *(datestr + 4) == '-' && *(datestr + 7) == '-') {
2616 
2617  TDS_YEAR = 0;
2618  TDS_MONTH = 1;
2619  TDS_DAY = 2;
2620  state = TDS_YEAR;
2621 
2622  }
2623  /* else we assume MDY */
2624  else {
2625  TDS_MONTH = 0;
2626  TDS_DAY = 1;
2627  TDS_YEAR = 2;
2628  state = TDS_MONTH;
2629  }
2630  for (s = datestr; *s; s++) {
2631  if (!isdigit((unsigned char) *s) && isdigit((unsigned char) last_char)) {
2632  state++;
2633  } else {
2634  if (state == TDS_MONTH)
2635  month = (month * 10) + (*s - '0');
2636  if (state == TDS_DAY)
2637  mday = (mday * 10) + (*s - '0');
2638  if (state == TDS_YEAR)
2639  year = (year * 10) + (*s - '0');
2640  }
2641  last_char = *s;
2642  }
2643 
2644  if (month > 0 && month < 13)
2645  t->tm_mon = month - 1;
2646  else
2647  return 0;
2648  if (mday > 0 && mday < 32)
2649  t->tm_mday = mday;
2650  else
2651  return 0;
2652 
2653  return store_year(year, t);
2654 
2655 }
2656 
2657 static int
2658 store_dd_mon_yyy_date(char *datestr, struct tds_time *t)
2659 {
2660 
2661  char dd[3];
2662  int mday;
2663  char mon[4];
2664  int year;
2665 
2666  tdsdump_log(TDS_DBG_INFO1, "store_dd_mon_yyy_date: %s\n", datestr);
2667  strlcpy(dd, datestr, 3);
2668  mday = atoi(dd);
2669 
2670  if (mday > 0 && mday < 32)
2671  t->tm_mday = mday;
2672  else
2673  return 0;
2674 
2675  if (datestr[2] == '-') {
2676  strlcpy(mon, &datestr[3], 4);
2677 
2678  if (store_monthname(mon, t) < 0) {
2679  tdsdump_log(TDS_DBG_INFO1, "store_dd_mon_yyy_date: store_monthname failed\n");
2680  return 0;
2681  }
2682 
2683  year = atoi(&datestr[7]);
2684  tdsdump_log(TDS_DBG_INFO1, "store_dd_mon_yyy_date: year %d\n", year);
2685 
2686  return store_year(year, t);
2687  } else {
2688  strlcpy(mon, &datestr[2], 4);
2689 
2690  if (store_monthname(mon, t) < 0) {
2691  tdsdump_log(TDS_DBG_INFO1, "store_dd_mon_yyy_date: store_monthname failed\n");
2692  return 0;
2693  }
2694 
2695  year = atoi(&datestr[5]);
2696  tdsdump_log(TDS_DBG_INFO1, "store_dd_mon_yyy_date: year %d\n", year);
2697 
2698  return store_year(year, t);
2699  }
2700 
2701 }
2702 
2703 /**
2704  * Test if a string is a month name and store correct month number
2705  * @return month number (0-11) or -1 if not match
2706  * @param datestr string to check
2707  * @param t where to store month (if NULL no store is done)
2708  */
2709 static int
2710 store_monthname(const char *datestr, struct tds_time *t)
2711 {
2712  int ret;
2713 
2714  tdsdump_log(TDS_DBG_INFO1, "store_monthname: %ld %s\n", (long) strlen(datestr), datestr);
2715  if (strlen(datestr) == 3) {
2716  if (strcasecmp(datestr, "jan") == 0)
2717  ret = 0;
2718  else if (strcasecmp(datestr, "feb") == 0)
2719  ret = 1;
2720  else if (strcasecmp(datestr, "mar") == 0)
2721  ret = 2;
2722  else if (strcasecmp(datestr, "apr") == 0)
2723  ret = 3;
2724  else if (strcasecmp(datestr, "may") == 0)
2725  ret = 4;
2726  else if (strcasecmp(datestr, "jun") == 0)
2727  ret = 5;
2728  else if (strcasecmp(datestr, "jul") == 0)
2729  ret = 6;
2730  else if (strcasecmp(datestr, "aug") == 0)
2731  ret = 7;
2732  else if (strcasecmp(datestr, "sep") == 0)
2733  ret = 8;
2734  else if (strcasecmp(datestr, "oct") == 0)
2735  ret = 9;
2736  else if (strcasecmp(datestr, "nov") == 0)
2737  ret = 10;
2738  else if (strcasecmp(datestr, "dec") == 0)
2739  ret = 11;
2740  else
2741  return -1;
2742  } else {
2743  if (strcasecmp(datestr, "january") == 0)
2744  ret = 0;
2745  else if (strcasecmp(datestr, "february") == 0)
2746  ret = 1;
2747  else if (strcasecmp(datestr, "march") == 0)
2748  ret = 2;
2749  else if (strcasecmp(datestr, "april") == 0)
2750  ret = 3;
2751  else if (strcasecmp(datestr, "june") == 0)
2752  ret = 5;
2753  else if (strcasecmp(datestr, "july") == 0)
2754  ret = 6;
2755  else if (strcasecmp(datestr, "august") == 0)
2756  ret = 7;
2757  else if (strcasecmp(datestr, "september") == 0)
2758  ret = 8;
2759  else if (strcasecmp(datestr, "october") == 0)
2760  ret = 9;
2761  else if (strcasecmp(datestr, "november") == 0)
2762  ret = 10;
2763  else if (strcasecmp(datestr, "december") == 0)
2764  ret = 11;
2765  else
2766  return -1;
2767  }
2768  if (t)
2769  t->tm_mon = ret;
2770  return ret;
2771 }
2772 
2773 static int
2774 store_yymmdd_date(const char *datestr, struct tds_time *t)
2775 {
2776  int month = 0, year = 0, mday = 0;
2777 
2778  int wholedate;
2779 
2780  wholedate = atoi(datestr);
2781 
2782  year = wholedate / 10000;
2783  month = (wholedate - (year * 10000)) / 100;
2784  mday = (wholedate - (year * 10000) - (month * 100));
2785 
2786  if (month > 0 && month < 13)
2787  t->tm_mon = month - 1;
2788  else
2789  return 0;
2790  if (mday > 0 && mday < 32)
2791  t->tm_mday = mday;
2792  else
2793  return 0;
2794 
2795  return (store_year(year, t));
2796 
2797 }
2798 
2799 static int
2800 store_time(const char *datestr, struct tds_time *t)
2801 {
2802  enum
2803  { TDS_HOURS,
2804  TDS_MINUTES,
2805  TDS_SECONDS,
2806  TDS_FRACTIONS
2807  };
2808 
2809  int state = TDS_HOURS;
2810  char last_sep = '\0';
2811  const char *s;
2812  unsigned int hours = 0, minutes = 0, seconds = 0, nanosecs = 0;
2813  int ret = 1;
2814  unsigned ns_div = 1;
2815 
2816  for (s = datestr; *s && strchr("apmAPM", (int) *s) == NULL; s++) {
2817  if (*s == ':' || *s == '.') {
2818  last_sep = *s;
2819  state++;
2820  } else {
2821  if (*s < '0' || *s > '9')
2822  ret = 0;
2823  switch (state) {
2824  case TDS_HOURS:
2825  hours = (hours * 10u) + (*s - '0');
2826  break;
2827  case TDS_MINUTES:
2828  minutes = (minutes * 10u) + (*s - '0');
2829  break;
2830  case TDS_SECONDS:
2831  seconds = (seconds * 10u) + (*s - '0');
2832  break;
2833  case TDS_FRACTIONS:
2834  if (ns_div < 1000000000u) {
2835  nanosecs = (nanosecs * 10u) + (*s - '0');
2836  ns_div *= 10;
2837  }
2838  break;
2839  }
2840  }
2841  }
2842  if (*s) {
2843  if (strcasecmp(s, "am") == 0) {
2844  if (hours == 12)
2845  hours = 0;
2846 
2847  t->tm_hour = hours;
2848  }
2849  if (strcasecmp(s, "pm") == 0) {
2850  if (hours == 0)
2851  ret = 0;
2852  if (hours > 0u && hours < 12u)
2853  t->tm_hour = hours + 12;
2854  else
2855  t->tm_hour = hours;
2856  }
2857  } else {
2858  if (hours < 24u)
2859  t->tm_hour = hours;
2860  else
2861  ret = 0;
2862  }
2863  if (minutes < 60u)
2864  t->tm_min = minutes;
2865  else
2866  ret = 0;
2867  if (seconds < 60u)
2868  t->tm_sec = seconds;
2869  else
2870  ret = 0;
2871  tdsdump_log(TDS_DBG_FUNC, "store_time() nanosecs = %d\n", nanosecs);
2872  if (nanosecs) {
2873  if (nanosecs < ns_div && last_sep == '.')
2874  t->tm_ns = nanosecs * (1000000000u / ns_div);
2875  else if (nanosecs < 1000u)
2876  t->tm_ns = nanosecs * 1000000u;
2877  else
2878  ret = 0;
2879  }
2880 
2881  return (ret);
2882 }
2883 
2884 static int
2885 store_hour(const char *hour, const char *ampm, struct tds_time *t)
2886 {
2887  int ret = 1;
2888  int hours;
2889 
2890  hours = atoi(hour);
2891 
2892  if (hours >= 0 && hours < 24) {
2893  if (strcasecmp(ampm, "am") == 0) {
2894  if (hours == 12)
2895  hours = 0;
2896 
2897  t->tm_hour = hours;
2898  }
2899  if (strcasecmp(ampm, "pm") == 0) {
2900  if (hours == 0)
2901  ret = 0;
2902  if (hours > 0 && hours < 12)
2903  t->tm_hour = hours + 12;
2904  else
2905  t->tm_hour = hours;
2906  }
2907  }
2908  return ret;
2909 }
2910 
2911 /**
2912  * Get same type but nullable
2913  * @param srctype type requires
2914  * @return nullable type
2915  */
2918 {
2919 
2920  switch (srctype) {
2921  case SYBCHAR:
2922  return SYBVARCHAR;
2923  break;
2924  case SYBINT1:
2925  case SYBUINT1:
2926  case SYBINT2:
2927  case SYBINT4:
2928  case SYBINT8:
2929  /* TODO sure ?? */
2930  case SYBUINT2:
2931  case SYBUINT4:
2932  case SYBUINT8:
2933  return SYBINTN;
2934  break;
2935  case SYBREAL:
2936  case SYBFLT8:
2937  return SYBFLTN;
2938  break;
2939  case SYBDATETIME:
2940  case SYBDATETIME4:
2941  return SYBDATETIMN;
2942  break;
2943  case SYBBIT:
2944  return SYBBITN;
2945  break;
2946  case SYBMONEY:
2947  case SYBMONEY4:
2948  return SYBMONEYN;
2949  break;
2950  case SYBTIME:
2951  return SYBTIMEN;
2952  break;
2953  case SYBDATE:
2954  return SYBDATEN;
2955  break;
2956  default:
2957  break;
2958  }
2959  return srctype;
2960 }
2961 
2962 /**
2963  * format a date string according to an "extended" strftime(3) formatting definition.
2964  * @param buf output buffer
2965  * @param maxsize size of buffer in bytes (space include terminator)
2966  * @param format format string passed to strftime(3), except that %z represents fraction of seconds.
2967  * @param dr date to convert
2968  * @param prec second fraction precision (0-7).
2969  * @return length of string returned, 0 for error
2970  */
2971 size_t
2972 tds_strftime(char *buf, size_t maxsize, const char *format, const TDSDATEREC * dr, int prec)
2973 {
2974  struct tm tm;
2975 
2976  size_t length;
2977  char *our_format;
2978  char *pz = NULL;
2979 
2980  assert(buf);
2981  assert(format);
2982  assert(dr);
2983  assert(0 <= dr->decimicrosecond && dr->decimicrosecond < 10000000);
2984  if (prec < 0 || prec > 7)
2985  prec = 3;
2986 
2987  tm.tm_sec = dr->second;
2988  tm.tm_min = dr->minute;
2989  tm.tm_hour = dr->hour;
2990  tm.tm_mday = dr->day;
2991  tm.tm_mon = dr->month;
2992  tm.tm_year = dr->year - 1900;
2993  tm.tm_wday = dr->weekday;
2994  tm.tm_yday = dr->dayofyear;
2995  tm.tm_isdst = 0;
2996 #ifdef HAVE_STRUCT_TM_TM_ZONE
2997  tm.tm_zone = NULL;
2998 #elif defined(HAVE_STRUCT_TM___TM_ZONE)
2999  tm.__tm_zone = NULL;
3000 #endif
3001 
3002  /* more characters are required because we replace %z with up to 7 digits */
3003  our_format = tds_new(char, strlen(format) + 1 + 5);
3004  if (!our_format)
3005  return 0;
3006 
3007  strcpy(our_format, format);
3008 
3009  /*
3010  * Look for "%z" in the format string. If found, replace it with dr->milliseconds.
3011  * For example, if milliseconds is 124, the format string
3012  * "%b %d %Y %H:%M:%S.%z" would become
3013  * "%b %d %Y %H:%M:%S.124".
3014  */
3015  for (pz = our_format; (pz = strstr(pz, "%z")) != NULL; pz++) {
3016  /* Skip any escaped cases (%%z) */
3017  if (pz > our_format && *(pz - 1) != '%')
3018  break;
3019  }
3020 
3021  if (pz) {
3022  if (prec || pz <= our_format || pz[-1] != '.') {
3023  char buf[12];
3024  sprintf(buf, "%07d", dr->decimicrosecond);
3025  memcpy(pz, buf, prec);
3026  strcpy(pz + prec, format + (pz - our_format) + 2);
3027  } else {
3028  strcpy(pz - 1, format + (pz - our_format) + 2);
3029  }
3030  }
3031 
3032  length = strftime(buf, maxsize, our_format, &tm);
3033 
3034  free(our_format);
3035 
3036  return length;
3037 }
3038 
3039 #if 0
3040 static TDS_UINT
3041 utf16len(const utf16_t * s)
3042 {
3043  const utf16_t *p = s;
3044 
3045  while (*p++)
3046  continue;
3047  return p - s;
3048 }
3049 #endif
3050 
3051 #include "tds_willconvert.h"
3052 
3053 /**
3054  * Test if a conversion is possible
3055  * @param srctype source type
3056  * @param desttype destination type
3057  * @return 0 if not convertible
3058  */
3059 unsigned char
3060 tds_willconvert(int srctype, int desttype)
3061 {
3062  TDS_TINYINT cat_from, cat_to;
3063  TDS_UINT yn;
3064 
3065  tdsdump_log(TDS_DBG_FUNC, "tds_willconvert(%d, %d)\n", srctype, desttype);
3066 
3067  /* they must be from 0 to 255 */
3068  if (((srctype|desttype) & ~0xff) != 0)
3069  return 0;
3070 
3071  cat_from = type2category[srctype];
3072  cat_to = type2category[desttype];
3073  yn = category_conversion[cat_from];
3074 
3075  yn = (yn >> cat_to) & 1;
3076 
3077  tdsdump_log(TDS_DBG_FUNC, "tds_willconvert(%d, %d) returns %s\n",
3078  srctype, desttype, yn? "yes":"no");
3079  return yn;
3080 }
3081 
3082 #if 0
3083 select day(d) as day, datepart(dw, d) as weekday, datepart(week, d) as week, d as 'date' from #t order by d
3084 day weekday week date
3085 ----------- ----------- ----------- ----------
3086  1 5 1 2009-01-01 Thursday
3087  2 6 1 2009-01-02 Friday
3088  3 7 1 2009-01-03 Saturday
3089  4 1 2 2009-01-04 Sunday
3090  5 2 2 2009-01-05
3091  6 3 2 2009-01-06
3092  7 4 2 2009-01-07
3093  8 5 2 2009-01-08
3094  9 6 2 2009-01-09
3095  10 7 2 2009-01-10
3096  11 1 3 2009-01-11
3097  12 2 3 2009-01-12
3098  13 3 3 2009-01-13
3099  14 4 3 2009-01-14
3100  15 5 3 2009-01-15
3101  16 6 3 2009-01-16
3102  17 7 3 2009-01-17
3103  18 1 4 2009-01-18
3104  19 2 4 2009-01-19
3105  20 3 4 2009-01-20
3106  21 4 4 2009-01-21
3107  22 5 4 2009-01-22
3108  23 6 4 2009-01-23
3109  24 7 4 2009-01-24
3110  25 1 5 2009-01-25
3111  26 2 5 2009-01-26
3112  27 3 5 2009-01-27
3113  28 4 5 2009-01-28
3114  29 5 5 2009-01-29
3115  30 6 5 2009-01-30
3116  31 7 5 2009-01-31
3117 #endif
3118 /**
3119  * Convert from db date format to a structured date format
3120  * @param datetype source date type. SYBDATETIME or SYBDATETIME4
3121  * @param di source date
3122  * @param dr destination date
3123  * @return TDS_FAIL or TDS_SUCCESS
3124  */
3125 TDSRET
3126 tds_datecrack(TDS_INT datetype, const void *di, TDSDATEREC * dr)
3127 {
3128  int dt_days;
3129  unsigned int dt_time;
3130 
3131  int years, months, days, ydays, wday, hours, mins, secs, dms, tzone = 0;
3132  int l, n, i, j;
3133 
3134  memset(dr, 0, sizeof(*dr));
3135 
3136  if (datetype == SYBMSDATE || datetype == SYBMSTIME
3137  || datetype == SYBMSDATETIME2 || datetype == SYBMSDATETIMEOFFSET) {
3138  const TDS_DATETIMEALL *dta = (const TDS_DATETIMEALL *) di;
3139  dt_days = (datetype == SYBMSTIME) ? 0 : dta->date;
3140  if (datetype == SYBMSDATE) {
3141  dms = 0;
3142  secs = 0;
3143  dt_time = 0;
3144  } else {
3145  dms = dta->time % 10000000u;
3146  dt_time = (unsigned int) (dta->time / 10000000u);
3147  secs = dt_time % 60;
3148  dt_time = dt_time / 60;
3149  }
3150  if (datetype == SYBMSDATETIMEOFFSET) {
3151  --dt_days;
3152  dt_time = dt_time + 1440 + dta->offset;
3153  dt_days += dt_time / 1440;
3154  dt_time %= 1440;
3155  tzone = dta->offset;
3156  }
3157  } else if (datetype == SYBDATETIME) {
3158  const TDS_DATETIME *dt = (const TDS_DATETIME *) di;
3159  dt_time = dt->dttime;
3160  dms = ((dt_time % 300) * 1000 + 150) / 300 * 10000u;
3161  dt_time = dt_time / 300;
3162  secs = dt_time % 60;
3163  dt_time = dt_time / 60;
3164  dt_days = dt->dtdays;
3165  } else if (datetype == SYBDATETIME4) {
3166  const TDS_DATETIME4 *dt4 = (const TDS_DATETIME4 *) di;
3167  secs = 0;
3168  dms = 0;
3169  dt_days = dt4->days;
3170  dt_time = dt4->minutes;
3171  } else if (datetype == SYBDATE) {
3172  dt_days = *((const TDS_DATE *) di);
3173  dms = 0;
3174  secs = 0;
3175  dt_time = 0;
3176  } else if (datetype == SYBTIME) {
3177  dt_time = *((const TDS_TIME *) di);
3178  dms = ((dt_time % 300) * 1000 + 150) / 300 * 10000u;
3179  dt_time = dt_time / 300;
3180  secs = dt_time % 60;
3181  dt_time = dt_time / 60;
3182  dt_days = 0;
3183  } else if (datetype == SYB5BIGTIME) {
3184  TDS_UINT8 bigtime = *((const TDS_BIGTIME *) di);
3185  dt_days = 0;
3186  dms = bigtime % 1000000u * 10u;
3187  dt_time = (bigtime / 1000000u) % 86400u;
3188  secs = dt_time % 60;
3189  dt_time = dt_time / 60u;
3190  } else if (datetype == SYB5BIGDATETIME) {
3191  TDS_UINT8 bigdatetime = *((const TDS_BIGDATETIME*) di);
3192  dms = bigdatetime % 1000000u * 10u;
3193  bigdatetime /= 1000000u;
3194  secs = bigdatetime % 60u;
3195  bigdatetime /= 60u;
3196  dt_time = bigdatetime % (24u*60u);
3197  dt_days = (int) (bigdatetime / (24u*60u) - BIGDATETIME_BIAS);
3198  } else {
3199  return TDS_FAIL;
3200  }
3201 
3202  /*
3203  * -53690 is minimun (1753-1-1) (Gregorian calendar start in 1732)
3204  * 2958463 is maximun (9999-12-31)
3205  */
3206  l = dt_days + (146038 + 146097*4);
3207  wday = (l + 4) % 7;
3208  n = (4 * l) / 146097; /* n century */
3209  l = l - (146097 * n + 3) / 4; /* days from xx00-02-28 (y-m-d) */
3210  i = (4000 * (l + 1)) / 1461001; /* years from xx00-02-28 */
3211  l = l - (1461 * i) / 4; /* year days from xx00-02-28 */
3212  ydays = l >= 306 ? l - 305 : l + 60;
3213  l += 31;
3214  j = (80 * l) / 2447;
3215  days = l - (2447 * j) / 80;
3216  l = j / 11;
3217  months = j + 1 - 12 * l;
3218  years = 100 * (n - 1) + i + l;
3219  if (l == 0 && (years & 3) == 0 && (years % 100 != 0 || years % 400 == 0))
3220  ++ydays;
3221 
3222  hours = dt_time / 60;
3223  mins = dt_time % 60;
3224 
3225  dr->year = years;
3226  dr->month = months;
3227  dr->quarter = months / 3;
3228  dr->day = days;
3229  dr->dayofyear = ydays;
3230  dr->weekday = wday;
3231  dr->hour = hours;
3232  dr->minute = mins;
3233  dr->second = secs;
3234  dr->decimicrosecond = dms;
3235  dr->timezone = tzone;
3236  return TDS_SUCCESS;
3237 }
3238 
3239 /**
3240  * \brief convert a number in string to TDS_INT
3241  *
3242  * \return TDS_CONVERT_* or failure code on error
3243  * \remarks Sybase's char->int conversion tolerates embedded blanks,
3244  * such that "convert( int, ' - 13 ' )" works.
3245  * If we find blanks, we copy the string to a temporary buffer,
3246  * skipping the blanks.
3247  * We return the results of atoi() with a clean string.
3248  *
3249  * n.b. it is possible to embed all sorts of non-printable characters, but we
3250  * only check for spaces. at this time, no one on the project has tested anything else.
3251  */
3252 static TDS_INT
3253 string_to_int(const char *buf, const char *pend, TDS_INT * res)
3254 {
3255  bool negative;
3256  unsigned int num; /* we use unsigned here for best overflow check */
3257  size_t digits, decimals;
3258 
3259  buf = parse_numeric(buf, pend, &negative, &digits, &decimals);
3260  if (!buf)
3261  return TDS_CONVERT_SYNTAX;
3262 
3263  num = 0;
3264  for (; digits; --digits, ++buf) {
3265  /* add a digit to number and check for overflow */
3266  /* NOTE I didn't forget a digit, I check overflow before multiply to prevent overflow */
3267  if (num > 214748364u)
3268  return TDS_CONVERT_OVERFLOW;
3269  num = num * 10u + (*buf - '0');
3270  }
3271 
3272  /* check for overflow and convert unsigned to signed */
3273  if (negative) {
3274  if (num > 2147483648u)
3275  return TDS_CONVERT_OVERFLOW;
3276  *res = 0 - num;
3277  } else {
3278  if (num >= 2147483648u)
3279  return TDS_CONVERT_OVERFLOW;
3280  *res = num;
3281  }
3282 
3283  return sizeof(TDS_INT);
3284 }
3285 
3286 /**
3287  * \brief convert a number in string to TDS_INT8
3288  *
3289  * \return TDS_CONVERT_* or failure code on error
3290  */
3291 static TDS_INT /* copied from string_ti_int and modified */
3292 parse_int8(const char *buf, const char *pend, TDS_UINT8 * res, bool * p_negative)
3293 {
3294  TDS_UINT8 num;
3295  size_t digits, decimals;
3296 
3297  buf = parse_numeric(buf, pend, p_negative, &digits, &decimals);
3298  if (!buf)
3299  return TDS_CONVERT_SYNTAX;
3300 
3301  num = 0;
3302  for (; digits; --digits, ++buf) {
3303  /* add a digit to number and check for overflow */
3304  TDS_UINT8 prev = num;
3305  if (num > (((TDS_UINT8) 1u) << 63) / 5u)
3306  return TDS_CONVERT_OVERFLOW;
3307  num = num * 10u + (*buf - '0');
3308  if (num < prev)
3309  return TDS_CONVERT_OVERFLOW;
3310  }
3311 
3312  *res = num;
3313  return sizeof(TDS_INT8);
3314 }
3315 
3316 /**
3317  * \brief convert a number in string to TDS_INT8
3318  *
3319  * \return TDS_CONVERT_* or failure code on error
3320  */
3321 static TDS_INT /* copied from string_ti_int and modified */
3322 string_to_int8(const char *buf, const char *pend, TDS_INT8 * res)
3323 {
3324  TDS_UINT8 num;
3325  TDS_INT parse_res;
3326  bool negative;
3327 
3328  parse_res = parse_int8(buf, pend, &num, &negative);
3329  if (parse_res < 0)
3330  return parse_res;
3331 
3332  /* check for overflow and convert unsigned to signed */
3333  if (negative) {
3334  if (num > (((TDS_UINT8) 1) << 63))
3335  return TDS_CONVERT_OVERFLOW;
3336  *res = 0 - num;
3337  } else {
3338  if (num >= (((TDS_UINT8) 1) << 63))
3339  return TDS_CONVERT_OVERFLOW;
3340  *res = num;
3341  }
3342  return sizeof(TDS_INT8);
3343 }
3344 
3345 /**
3346  * \brief convert a number in string to TDS_UINT8
3347  *
3348  * \return TDS_CONVERT_* or failure code on error
3349  */
3350 static TDS_INT /* copied from string_to_int8 and modified */
3351 string_to_uint8(const char *buf, const char *pend, TDS_UINT8 * res)
3352 {
3353  TDS_UINT8 num;
3354  TDS_INT parse_res;
3355  bool negative;
3356 
3357  parse_res = parse_int8(buf, pend, &num, &negative);
3358  if (parse_res < 0)
3359  return parse_res;
3360 
3361  /* check for overflow */
3362  if (negative && num)
3363  return TDS_CONVERT_OVERFLOW;
3364 
3365  *res = num;
3366  return sizeof(TDS_UINT8);
3367 }
3368 
3369 /**
3370  * Parse a string for numbers.
3371  *
3372  * Syntax can be something like " *[+-] *[0-9]*\.[0-9]* *".
3373  *
3374  * The function ignore all spaces. It strips leading zeroes which could
3375  * possibly lead to overflow.
3376  * The function returns a pointer to the integer part followed by *p_digits
3377  * digits followed by a dot followed by *p_decimals digits (dot and
3378  * fractional digits are optional, in this case *p_decimals is 0).
3379  *
3380  * @param buf start of string
3381  * @param pend pointer to string end
3382  * @param p_negative store if number is negative
3383  * @param p_digits store number of integer digits
3384  * @param p_decimals store number of fractional digits
3385  * @return pointer to first not zero digit. If NULL this indicate a syntax
3386  * error.
3387  */
3388 static const char *
3389 parse_numeric(const char *buf, const char *pend, bool *p_negative, size_t *p_digits, size_t *p_decimals)
3390 {
3391  enum { blank = ' ' };
3392 #define SKIP_IF(cond) while (p != pend && (cond)) ++p;
3393  const char *p, *start;
3394  bool negative = false;
3395 
3396  *p_decimals = 0;
3397  p = buf;
3398 
3399  /* ignore leading spaces */
3400  SKIP_IF(*p == blank);
3401  if (p == pend) {
3402  *p_negative = false;
3403  *p_digits = 0;
3404  return p;
3405  }
3406 
3407  /* check for sign */
3408  switch (*p) {
3409  case '-':
3410  negative = true;
3411  /* fall thru */
3412  case '+':
3413  /* skip spaces between sign and number */
3414  ++p;
3415  SKIP_IF(*p == blank);
3416  break;
3417  }
3418  *p_negative = negative;
3419 
3420  /* a digit must be present */
3421  if (p == pend)
3422  return NULL;
3423 
3424  /*
3425  * skip leading zeroes
3426  * Not skipping them cause numbers like "000000000000" to
3427  * appear like overflow
3428  */
3429  SKIP_IF(*p == '0');
3430 
3431  start = p;
3432  SKIP_IF(TDS_ISDIGIT(*p));
3433  *p_digits = p - start;
3434 
3435  /* parse decimal part */
3436  if (p != pend && *p == '.') {
3437  const char *decimals_start = ++p;
3438  SKIP_IF(TDS_ISDIGIT(*p));
3439  *p_decimals = p - decimals_start;
3440  }
3441 
3442  /* check for trailing spaces */
3443  SKIP_IF(*p == blank);
3444  if (p != pend)
3445  return NULL;
3446 
3447  return start;
3448 }
3449 
3450 static TDS_INT
3451 string_to_float(const TDS_CHAR * src, TDS_UINT srclen, int desttype, CONV_RESULT * cr)
3452 {
3453  char tmpstr[128];
3454  char *end;
3455  double res;
3456 
3457  /* ignore leading spaces */
3458  while (srclen > 0 && src[0] == ' ')
3459  ++src, --srclen;
3460 
3461  /* ignore trailing blanks and nulls */
3462  while (srclen > 0 && (src[srclen - 1] == ' ' || src[srclen - 1] == '\0'))
3463  --srclen;
3464 
3465  if (srclen >= sizeof(tmpstr))
3466  return TDS_CONVERT_OVERFLOW;
3467 
3468  memcpy(tmpstr, src, srclen);
3469  tmpstr[srclen] = 0;
3470 
3471  errno = 0;
3472  res = strtod(tmpstr, &end);
3473  if (errno == ERANGE)
3474  return TDS_CONVERT_OVERFLOW;
3475  if (end != tmpstr + srclen)
3476  return TDS_CONVERT_SYNTAX;
3477 
3478  if (desttype == SYBREAL) {
3479  /* FIXME check overflows */
3480  cr->r = (TDS_REAL)res;
3481  return sizeof(TDS_REAL);
3482  }
3483  cr->f = res;
3484  return sizeof(TDS_FLOAT);
3485 }
3486 
3487 /** @} */
#define TDS_GET_UA4BE(ptr)
Definition: bytes.h:72
#define TDS_GET_UA2BE(ptr)
Definition: bytes.h:57
#define TDS_PUT_UA4BE(ptr, val)
Definition: bytes.h:81
#define TDS_CONVERT_SYNTAX
Definition: convert.h:78
#define TDS_CONVERT_BINARY
Definition: convert.h:84
#define TDS_CONVERT_OVERFLOW
Definition: convert.h:80
#define TDS_CONVERT_NOAVAIL
Definition: convert.h:77
#define TDS_CONVERT_CHAR
Definition: convert.h:83
#define TDS_CONVERT_FAIL
Definition: convert.h:76
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
const char * months[]
Definition: ftaerr.cpp:118
static char precision
Definition: genparams.c:28
#define NULL
Definition: ncbistd.hpp:225
static TDS_INT tds_convert_int(TDS_INT num, int desttype, CONV_RESULT *cr)
Definition: convert.c:624
static TDS_INT string_to_int(const char *buf, const char *pend, TDS_INT *res)
convert a number in string to TDS_INT
Definition: convert.c:3253
static bool is_numeric(const char *)
Definition: convert.c:2536
#define string_to_result(s, cr)
Definition: convert.c:175
static TDS_INT tds_convert_real(const TDS_REAL *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:1497
static TDS_INT string_to_result_(int desttype, const char *s, CONV_RESULT *cr)
Copy a terminated string to result and return len or TDS_CONVERT_NOMEM.
Definition: convert.c:161
static TDS_INT tds_convert_bigdatetime(const TDSCONTEXT *tds_ctx, const TDS_BIGDATETIME *bigdatetime, int desttype, CONV_RESULT *cr)
Definition: convert.c:1473
static int store_monthname(const char *, struct tds_time *)
Test if a string is a month name and store correct month number.
Definition: convert.c:2710
static TDS_INT tds_convert_bit(const TDS_CHAR *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:558
static TDS_INT tds_convert_int_numeric(unsigned char scale, unsigned char sign, TDS_UINT num, CONV_RESULT *cr)
Definition: convert.c:597
static TDS_INT tds_convert_int1(const TDS_TINYINT *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:564
static TDS_INT tds_convert_money(const TDS_MONEY *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:1161
static int string_to_numeric(const char *instr, const char *pend, CONV_RESULT *cr)
convert a number in string to a TDSNUMERIC
Definition: convert.c:2270
static int store_time(const char *, struct tds_time *)
Definition: convert.c:2800
static TDS_INT string_to_float(const TDS_CHAR *src, TDS_UINT srclen, int desttype, CONV_RESULT *cr)
Definition: convert.c:3451
static TDS_INT tds_convert_datetimeall(const TDSCONTEXT *tds_ctx, int srctype, const TDS_DATETIMEALL *dta, int desttype, CONV_RESULT *cr)
Definition: convert.c:1263
static TDS_INT tds_convert_date(const TDSCONTEXT *tds_ctx, const TDS_DATE *date, int desttype, CONV_RESULT *cr)
Definition: convert.c:1439
static TDS_INT tds_convert_unique(const TDS_CHAR *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:1711
static int stringz_to_numeric(const char *instr, CONV_RESULT *cr)
convert a zero terminated string to NUMERIC
Definition: convert.c:2264
static int string_to_datetime(const char *datestr, TDS_UINT len, int desttype, CONV_RESULT *cr)
Definition: convert.c:1991
static TDS_INT tds_convert_uint8(const TDS_UINT8 *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:794
static bool is_dd_mon_yyyy(char *t)
Definition: convert.c:2431
static bool is_ampm(const char *)
Definition: convert.c:2512
static const char * parse_numeric(const char *buf, const char *pend, bool *p_negative, size_t *p_digits, size_t *p_decimals)
Parse a string for numbers.
Definition: convert.c:3389
static TDS_INT tds_convert_bigtime(const TDSCONTEXT *tds_ctx, const TDS_BIGTIME *bigtime, int desttype, CONV_RESULT *cr)
Definition: convert.c:1455
static TDS_INT tds_convert_datetime4(const TDSCONTEXT *tds_ctx, const TDS_DATETIME4 *dt4, int desttype, CONV_RESULT *cr)
Definition: convert.c:1407
static TDS_INT tds_convert_uint2(const TDS_USMALLINT *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:576
static TDS_INT tds_convert_char(const TDS_CHAR *src, TDS_UINT srclen, int desttype, CONV_RESULT *cr)
Definition: convert.c:338
TDS_SERVER_TYPE tds_get_null_type(TDS_SERVER_TYPE srctype)
Get same type but nullable.
Definition: convert.c:2917
static bool is_timeformat(const char *)
Definition: convert.c:2548
static int store_year(int, struct tds_time *)
Definition: convert.c:2563
static int store_yymmdd_date(const char *, struct tds_time *)
Definition: convert.c:2774
static TDS_INT tds_convert_int8_numeric(unsigned char scale, unsigned char sign, TDS_UINT8 num, CONV_RESULT *cr)
Definition: convert.c:610
#define CASE_ALL_CHAR
Definition: convert.c:195
unsigned char tds_willconvert(int srctype, int desttype)
Test if a conversion is possible.
Definition: convert.c:3060
TDSRET tds_datecrack(TDS_INT datetype, const void *di, TDSDATEREC *dr)
Convert from db date format to a structured date format.
Definition: convert.c:3126
static TDS_INT tds_convert_time(const TDSCONTEXT *tds_ctx, const TDS_TIME *time, int desttype, CONV_RESULT *cr)
Definition: convert.c:1423
static TDS_INT tds_convert_datetime(const TDSCONTEXT *tds_ctx, const TDS_DATETIME *dt, int desttype, unsigned precision, CONV_RESULT *cr)
Definition: convert.c:1332
size_t tds_strftime(char *buf, size_t maxsize, const char *format, const TDSDATEREC *dr, int prec)
format a date string according to an "extended" strftime(3) formatting definition.
Definition: convert.c:2972
ssize_t tds_char2hex(TDS_CHAR *dest, size_t destlen, const TDS_CHAR *src, size_t srclen)
Definition: convert.c:296
static TDS_INT string_to_int8(const char *buf, const char *pend, TDS_INT8 *res)
convert a number in string to TDS_INT8
Definition: convert.c:3322
static TDS_INT tds_convert_money4(const TDS_MONEY4 *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:1048
#define is_monthname(s)
Definition: convert.c:147
TDS_INT tds_convert(const TDSCONTEXT *tds_ctx, int srctype, const TDS_CHAR *src, TDS_UINT srclen, int desttype, CONV_RESULT *cr)
tds_convert convert a type to another.
Definition: convert.c:1882
static TDS_INT tds_convert_int2(const TDS_SMALLINT *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:570
static TDS_INT tds_convert_flt8(const TDS_FLOAT *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:1611
static TDS_INT binary_to_result(int desttype, const void *data, size_t len, CONV_RESULT *cr)
Copy binary data to to result and return len or TDS_CONVERT_NOMEM.
Definition: convert.c:182
static TDS_INT tds_convert_binary(const TDS_UCHAR *src, TDS_INT srclen, int desttype, CONV_RESULT *cr)
Definition: convert.c:214
static TDS_INT tds_convert_numeric(const TDS_NUMERIC *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:870
static TDS_INT tds_convert_uint4(const TDS_UINT *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:588
static int store_dd_mon_yyy_date(char *datestr, struct tds_time *t)
Definition: convert.c:2658
static TDS_INT tds_convert_to_binary(int srctype, const TDS_CHAR *src, TDS_UINT srclen, int desttype, CONV_RESULT *cr)
Definition: convert.c:1761
static int store_hour(const char *, const char *, struct tds_time *)
Definition: convert.c:2885
static TDS_INT parse_int8(const char *buf, const char *pend, TDS_UINT8 *res, bool *p_negative)
convert a number in string to TDS_INT8
Definition: convert.c:3292
static TDS_INT tds_convert_int8(const TDS_INT8 *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:717
static bool is_numeric_dateformat(const char *)
Definition: convert.c:2390
static bool is_alphabetic(const char *)
Definition: convert.c:2524
static TDS_INT string_to_uint8(const char *buf, const char *pend, TDS_UINT8 *res)
convert a number in string to TDS_UINT8
Definition: convert.c:3351
const char tds_hex_digits[]
Definition: convert.c:155
static int store_numeric_date(const char *, struct tds_time *)
Definition: convert.c:2602
static int store_mday(const char *, struct tds_time *)
Definition: convert.c:2590
static TDS_INT tds_convert_int4(const TDS_INT *src, int desttype, CONV_RESULT *cr)
Definition: convert.c:582
#define CASE_ALL_BINARY
Definition: convert.c:199
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
char * buf
int i
if(yy_accept[yy_current_state])
yy_size_t n
int len
#define strcasecmp
EIPRangeType t
Definition: ncbi_localip.c:101
int ssize_t
Definition: ncbiconf_msvc.h:92
int isalpha(Uchar c)
Definition: ncbictype.hpp:61
int isdigit(Uchar c)
Definition: ncbictype.hpp:64
T negative(T x_)
static Format format
Definition: njn_ioutil.cpp:53
std::istream & in(std::istream &in_, double &x_)
static char tmp[2048]
Definition: utf8.c:42
union tdsmoney TDS_MONEY
TDS_UINT8 TDS_BIGTIME
Definition: proto.h:72
struct tdsdatetime4 TDS_DATETIME4
TDS_SERVER_TYPE
Definition: proto.h:161
@ SYBTIMEN
Definition: proto.h:226
@ SYBVARIANT
Definition: proto.h:200
@ SYBUINT8
Definition: proto.h:215
@ SYBUNIQUE
Definition: proto.h:199
@ SYBUINT2
Definition: proto.h:213
@ SYBDATEN
Definition: proto.h:219
@ SYBUINT4
Definition: proto.h:214
@ SYB5BIGTIME
Definition: proto.h:231
@ SYB5BIGDATETIME
Definition: proto.h:230
@ SYBUINT1
Definition: proto.h:212
struct tdsunique TDS_UNIQUE
TDS_UINT8 TDS_BIGDATETIME
Definition: proto.h:73
struct tdsnumeric TDS_NUMERIC
TDS_INT TDS_DATE
Definition: proto.h:69
TDS_INT TDS_TIME
Definition: proto.h:70
struct tdsmoney4 TDS_MONEY4
struct tdsdatetime TDS_DATETIME
#define tds_numeric_to_string
#define tds_get_size_by_type
#define tds_prtype
#define tds_strndup
#define tds_money_to_string
#define tds_numeric_bytes_per_prec
#define tds_numeric_change_prec_scale
#define strlcpy(d, s, l)
Definition: replacements.h:80
#define strtok_r
Definition: replacements.h:68
#define assert(x)
Definition: srv_diag.hpp:58
this structure is not directed connected to a TDS protocol but keeps any DATE/TIME information.
Definition: tds.h:167
TDS_USMALLINT has_date
Definition: tds.h:174
TDS_INT date
date, 0 = 1900-01-01
Definition: tds.h:169
TDS_SMALLINT offset
time offset
Definition: tds.h:170
TDS_USMALLINT time_prec
Definition: tds.h:171
TDS_USMALLINT has_time
Definition: tds.h:173
TDS_USMALLINT has_offset
Definition: tds.h:175
TDS_UINT8 time
time, 7 digit precision
Definition: tds.h:168
TDS_UINT len
Definition: convert.h:68
TDS_CHAR * ib
Definition: convert.h:67
TDS_UINT len
Definition: convert.h:64
TDS_CHAR * c
Definition: convert.h:63
TDSLOCALE * locale
Definition: tds.h:1099
char * date_fmt
Definition: tds.h:650
int tm_ns
nanoseconds (0-999999999)
Definition: convert.c:62
int tm_year
year (0=1900)
Definition: convert.c:56
int tm_hour
hours (0-23)
Definition: convert.c:59
int tm_mday
month day (1-31)
Definition: convert.c:58
int tm_min
minutes (0-59)
Definition: convert.c:60
int tm_mon
month (0-11)
Definition: convert.c:57
int tm_sec
seconds (0-59)
Definition: convert.c:61
Store variant informations.
Definition: tds.h:669
TDS_CHAR * data
Definition: tds.h:671
TDS_SERVER_TYPE type
Definition: tds.h:674
TDS_INT data_len
Definition: tds.h:673
Used by tds_datecrack.
Definition: tds.h:180
TDS_USMALLINT days
Definition: proto.h:57
TDS_USMALLINT minutes
Definition: proto.h:58
TDS_INT dtdays
Definition: proto.h:51
TDS_INT dttime
Definition: proto.h:52
TDS_INT mny4
Definition: proto.h:46
unsigned char scale
Definition: proto.h:28
unsigned char precision
Definition: proto.h:27
unsigned char array[33]
Definition: proto.h:29
TDS_INT mnyhigh
Definition: proto.h:34
TDS_UINT mnylow
Definition: proto.h:35
TDS_USMALLINT Data3
Definition: proto.h:65
TDS_UCHAR Data4[8]
Definition: proto.h:66
TDS_UINT Data1
Definition: proto.h:63
TDS_USMALLINT Data2
Definition: proto.h:64
#define SYBMSDATE
Definition: sybdb.h:222
#define SYBINT4
Definition: sybdb.h:170
#define SYBNUMERIC
Definition: sybdb.h:202
#define SYBVARCHAR
Definition: sybdb.h:162
#define SYBDATE
Definition: sybdb.h:214
#define SYBINT8
Definition: sybdb.h:172
#define SYBMONEYN
Definition: sybdb.h:208
#define SYBMSDATETIME2
Definition: sybdb.h:226
#define SYBINTN
Definition: sybdb.h:164
#define SYBMSDATETIMEOFFSET
Definition: sybdb.h:228
#define SYBINT1
Definition: sybdb.h:166
#define SYBDATETIME4
Definition: sybdb.h:192
#define SYBDECIMAL
Definition: sybdb.h:204
#define SYBCHAR
Definition: sybdb.h:160
#define SYBREAL
Definition: sybdb.h:194
#define SYBDATETIMN
Definition: sybdb.h:210
#define SYBBITN
Definition: sybdb.h:180
#define SYBTIME
Definition: sybdb.h:216
#define SYBMSTIME
Definition: sybdb.h:224
#define SYBDATETIME
Definition: sybdb.h:176
#define SYBMONEY
Definition: sybdb.h:190
#define SYBMONEY4
Definition: sybdb.h:188
#define SYBFLT8
Definition: sybdb.h:174
#define SYBFLTN
Definition: sybdb.h:206
#define SYBINT2
Definition: sybdb.h:168
#define SYBBIT
Definition: sybdb.h:178
#define PRIu64
#define PRId64
#define TDS_INT8_MAX
Definition: convert.c:95
#define IS_TINYINT(x)
Definition: convert.c:81
#define TDS_ISDIGIT(c)
Definition: convert.c:102
#define IS_INT(x)
Definition: convert.c:90
#define TDS_INT8_MIN
Definition: convert.c:96
unsigned short utf16_t
Definition: convert.c:52
#define TDS_INT_MAX
Definition: convert.c:89
#define IS_UINT(x)
Definition: convert.c:93
#define TDS_INT_MIN
Definition: convert.c:88
#define BIGDATETIME_BIAS
Definition: convert.c:104
#define IS_USMALLINT(x)
Definition: convert.c:83
#define IS_UINT8(x)
Definition: convert.c:100
#define SKIP_IF(cond)
#define TDS_UINT8_MAX
Definition: convert.c:99
#define test_alloc(x)
Definition: convert.c:79
#define IS_SMALLINT(x)
Definition: convert.c:82
Main include file for libtds.
#define TDS_FAIL
Definition: tds.h:204
#define tds_new(type, n)
Definition: tds.h:1392
tds_sysdep_int32_type TDS_INT
Definition: tds.h:149
#define tdsdump_log
Definition: tds.h:1561
#define TDS_DBG_INFO1
Definition: tds.h:900
tds_sysdep_real64_type TDS_FLOAT
Definition: tds.h:152
tds_sysdep_int64_type TDS_INT8
Definition: tds.h:153
unsigned char TDS_UCHAR
Definition: tds.h:145
tds_sysdep_real32_type TDS_REAL
Definition: tds.h:151
unsigned char TDS_TINYINT
Definition: tds.h:146
tds_sysdep_int16_type TDS_SMALLINT
Definition: tds.h:147
char TDS_CHAR
Definition: tds.h:144
tds_sysdep_uint64_type TDS_UINT8
Definition: tds.h:154
int TDSRET
Definition: tds.h:201
tds_sysdep_uint16_type TDS_USMALLINT
Definition: tds.h:148
#define TDS_SUCCESS
Definition: tds.h:203
tds_sysdep_uint32_type TDS_UINT
Definition: tds.h:150
#define MAXPRECISION
Definition: tds.h:470
#define TDS_DBG_FUNC
Definition: tds.h:898
static const TDS_UINT category_conversion[]
static const TDS_TINYINT type2category[256]
TDS_TINYINT ti
Definition: convert.h:36
TDS_BIGTIME bigtime
Definition: convert.h:52
TDS_UINT ui
Definition: convert.h:40
TDS_DATETIMEALL dta
Definition: convert.h:49
TDS_DATETIME dt
Definition: convert.h:47
TDS_DATE date
Definition: convert.h:51
TDS_SMALLINT si
Definition: convert.h:37
TDS_INT i
Definition: convert.h:39
struct conv_result::cb_t cb
TDS_CHAR * ib
Definition: convert.h:59
TDS_USMALLINT usi
Definition: convert.h:38
TDS_NUMERIC n
Definition: convert.h:54
TDS_UINT8 ubi
Definition: convert.h:42
TDS_UNIQUE u
Definition: convert.h:55
struct conv_result::cc_t cc
TDS_MONEY m
Definition: convert.h:45
TDS_INT8 bi
Definition: convert.h:41
TDS_REAL r
Definition: convert.h:44
TDS_MONEY4 m4
Definition: convert.h:46
TDS_BIGDATETIME bigdatetime
Definition: convert.h:53
TDS_TIME time
Definition: convert.h:50
TDS_FLOAT f
Definition: convert.h:43
TDS_DATETIME4 dt4
Definition: convert.h:48
TDS_CHAR * c
Definition: convert.h:58
Definition: proto.h:39
TDS_INT8 mny
Definition: proto.h:41
TDS_OLD_MONEY tdsoldmoney
Definition: proto.h:40
void free(voidpf ptr)
Modified on Sat Dec 02 09:22:24 2023 by modify_doxy.py rev. 669887