CUBRID Engine  latest
cnv.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * cnv.c - String conversion functions
21  */
22 
23 #ident "$Id$"
24 
25 #include "config.h"
26 
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <float.h>
32 #include <math.h>
33 #include <time.h>
34 #include <stdarg.h>
35 #include <wchar.h>
36 
37 #include "porting.h"
38 #include "adjustable_array.h"
39 #include "intl_support.h"
40 #include "memory_alloc.h"
41 #include "string_opfunc.h"
42 #include "object_domain.h"
43 #include "language_support.h"
44 #include "object_primitive.h"
45 #include "cnv.h"
46 #include "cnvlex.h"
47 #include "cnverr.h"
48 #if defined(SERVER_MODE)
49 #include "critical_section.h"
50 #endif
51 #include "tz_support.h"
52 #include "db_date.h"
53 #include "dbtype.h"
54 #if defined (SERVER_MODE)
55 #include "thread_manager.hpp" // for thread_get_thread_entry_info
56 #endif // SERVER_MODE
57 
58 #if defined (SUPPRESS_STRLEN_WARNING)
59 #define strlen(s1) ((int) strlen(s1))
60 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
61 
62 #define BITS_IN_BYTE 8
63 #define HEX_IN_BYTE 2
64 #define BITS_IN_HEX 4
65 
66 /*
67  * 2**3.1 ~ 10. Thus a string with one decimal value per byte will be (8/3.1)
68  * times longer than a string with 8 binary places per byte.
69  * A 'decimal string' needs to be 3 times longer than a raw numeric string
70  * plus a sign and a NULL termination.
71  */
72 #define DEC_BUFFER_SIZE (DB_NUMERIC_BUF_SIZE * 6) + 2
73 #define GET_MIN(a, b) (a < b) ? a : b
74 #define BYTE_COUNT(bit_cnt) (((bit_cnt)+BITS_IN_BYTE-1)/BITS_IN_BYTE)
75 #define BYTE_COUNT_HEX(bit_cnt) (((bit_cnt)+BITS_IN_HEX-1)/BITS_IN_HEX)
76 
77 #define CNV_ERR_BAD_BINARY_DIGIT -1
78 #define CNV_ERR_BAD_HEX_DIGIT -2
79 #define CNV_ERR_NO_MEMORY -3
80 
81 /* Maximum number of digits in a numeric string. */
82 #define FMT_MAX_DIGITS \
83 (fmt_max_digits? \
84  fmt_max_digits : \
85  (fmt_max_digits = (int)ceil(DBL_MAX_EXP * log10( (double) FLT_RADIX))))
86 
87 /* Maximum number of CHARACTERS in a local date value string. */
88 #define FMT_MAX_DATE_STRING 32
89 
90 /* Maximum number of CHARACTERS in a local time value string. */
91 #define FMT_MAX_TIME_STRING 32
92 
93 /* Maximum number of CHARACTERS in a local mtime value string. */
94 #define FMT_MAX_MTIME_STRING 36
95 
96 /* Maximum number of CHARACTERS in a local timestamp value string. */
97 #define FMT_MAX_TIMESTAMP_STRING \
98  (FMT_MAX_DATE_STRING + FMT_MAX_TIME_STRING + 1)
99 
100 /* Maximum number of CHARACTERS in a local datetime value string. */
101 #define FMT_MAX_DATETIME_STRING \
102  (FMT_MAX_DATE_STRING + FMT_MAX_MTIME_STRING + 1)
103 
104 #define mbs_eql(s1, s2) !strcmp(s1, s2)
105 #define wcs_eql(ws1, ws2) !wcscmp(ws1, ws2)
106 
107 /* US Zone Definitions */
108 #define LOCAL_STAR "*"
109 #define LOCAL_MINUS "-"
110 #define LOCAL_PLUS "+"
111 #define LOCAL_SPACE " "
112 #define LOCAL_0 "0"
113 #define LOCAL_EXP_LENGTH "E+dd"
114 #define LOCAL_EXP "E"
115 #define LOCAL_SLASH "/"
116 #define LOCAL_COLON ":"
117 #define WCSCAT( buffer, wcs1, wcs2) \
118  (wcscpy( buffer, wcs1), wcscpy( buffer + wcslen( wcs1), wcs2), buffer)
119 
120 #define FMT_SCIENTIFIC() L"E"
121 #define FMT_THOUSANDS() L","
122 #define FMT_DECIMAL() L"."
123 #define FMT_Z() L"Z"
124 #define FMT_9() L"9"
125 #define FMT_X() L"X"
126 #define FMT_STAR() L"*"
127 #define FMT_PLUS() L"+"
128 #define FMT_CURRENCY() L"$"
129 #define FMT_DIGITS() L"0123456789"
130 
131 
132 #define KOREAN_EUC_YEAR_SYMBOL "\xb3\xe2" /* nyeon */
133 #define KOREAN_EUC_MONTH_SYMBOL "\xbf\xf9" /* wol */
134 #define KOREAN_EUC_DAY_SYMBOL "\xc0\xcf" /* il */
135 
136 #if !defined (SERVER_MODE)
137 /* no critical section */
138 #define csect_enter(a, b, c) NO_ERROR
139 #define csect_exit(a, b)
140 #endif /* !defined (SERVER_MODE) */
141 
142 
143 /* Format Descriptors */
144 typedef enum
145 {
149 } FORMAT_DIGIT;
150 
151 typedef enum
152 {
157 
160 {
163  bool thousands;
164  bool decimal;
169 };
170 
173 {
175  bool thousands;
178  const char *pattern;
179 };
180 
183 {
184  bool thousands;
185  bool decimal;
193 };
194 
196 {
200 
201 /*
202  * Utility Functions
203  */
204 /* US Zone Functions */
205 static const char *us_date_string (int month, int day, int year);
206 static int us_date_value (int *the_month, int *the_day, int *the_year);
207 static const char *us_time_string (const DB_TIME * the_time);
208 static int us_time_value (int *the_hour, int *the_min, int *the_sec);
209 #if defined(ENABLE_UNUSED_FUNCTION)
210 static const char *us_alt_date_string (int month, int day, int year);
211 static int us_alt_date_value (int *the_month, int *the_day, int *the_year);
212 static const char *us_mtime_string (int hour, int minute, int second, int millisecond);
213 static int us_mtime_value (int *the_hour, int *the_min, int *the_sec, int *the_msec);
214 static const char *us_timestamp_string (const DB_TIMESTAMP * the_timestamp);
215 static int us_timestamp_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec);
216 static const char *us_datetime_string (const DB_DATETIME * the_datetime);
217 static int us_datetime_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec,
218  int *the_msec);
219 #endif
220 
221 /* KO Zone Functions */
222 static const char *ko_date_string (int month, int day, int year);
223 static int ko_date_value (int *the_month, int *the_day, int *the_year);
224 static const char *ko_time_string (const DB_TIME * the_time);
225 static int ko_time_value (int *the_hour, int *the_min, int *the_sec);
226 #if defined(ENABLE_UNUSED_FUNCTION)
227 static const char *ko_mtime_string (int hour, int minute, int second, int millisecond);
228 static const char *ko_alt_date_string (int month, int day, int year);
229 static int ko_alt_date_value (int *the_month, int *the_day, int *the_year);
230 static int ko_mtime_value (int *the_hour, int *the_min, int *the_sec, int *the_msec);
231 static const char *ko_timestamp_string (const DB_TIMESTAMP * the_timestamp);
232 static int ko_timestamp_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec);
233 static const char *ko_datetime_string (const DB_DATETIME * the_datetime);
234 static int ko_datetime_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec,
235  int *the_msec);
236 static wchar_t ko_euc_year_wc (void);
237 static wchar_t ko_euc_month_wc (void);
238 static wchar_t ko_euc_day_wc (void);
239 #endif
240 static const char *local_am (void);
241 static const char *local_pm (void);
242 
243 /* Utility Functions */
244 static int fmt_minute_value (const char *, int *);
245 static int fmt_second_value (const char *, int *);
246 #if defined (ENABLE_UNUSED_FUNCTION)
247 static int fmt_millisecond_value (const char *descriptor, int *the_msec);
248 #endif
249 
250 static const char *local_am_pm_string (const DB_TIME * the_time);
251 static int local_am_pm_value (bool *);
252 
253 static const char *local_grouping (void);
254 static const char *local_thousands (void);
255 static const char *local_decimal (void);
256 static const char *local_date_string (int month, int day, int year);
257 static int local_date_value (int *, int *, int *);
258 static const char *local_time_string (const DB_TIME * the_time);
259 static int local_time_value (int *, int *, int *);
260 #if defined(ENABLE_UNUSED_FUNCTION)
261 static const char *local_timestamp_string (const DB_TIMESTAMP * the_timestamp);
262 static int local_timestamp_value (int *, int *, int *, int *, int *, int *);
263 static const char *local_long_month_name (int month);
264 static const char *local_long_weekday_name (int weekday);
265 static const char *local_short_month_name (int month);
266 static const char *local_short_weekday_name (int weekday);
267 static const char *local_datetime_string (const DB_DATETIME * the_timestamp);
268 static const char *local_alt_date_string (int month, int day, int year);
269 static int local_alt_date_value (int *, int *, int *);
270 static int local_datetime_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec,
271  int *the_msec);
272 #endif
273 
274 static const wchar_t *cnv_wcs (const char *mbs);
275 static ADJ_ARRAY *cnv_get_value_string_buffer (int nchars);
276 static int cnv_bad_char (const char *string, bool unknown);
277 static INTL_ZONE cnv_currency_zone (DB_CURRENCY currency);
278 #if defined (ENABLE_UNUSED_FUNCTION)
279 static ADJ_ARRAY *cnv_get_string_buffer (int nchars);
280 static const char *cnv_currency_symbol (DB_CURRENCY currency);
281 static bool cnv_valid_timestamp (DB_DATE * the_date, DB_TIME * the_time);
282 static int fmt_validate (const char *format, FMT_LEX_MODE mode, FMT_TOKEN_TYPE token_type, DB_TYPE data_type);
283 #endif /* ENABLE_UNUSED_FUNCTION */
284 static bool cnv_valid_currency (DB_CURRENCY currency);
285 
286 static int fmt_integral_digits (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands,
287  double *the_value, int *nfound);
288 static int fmt_integral_value (FORMAT_DIGIT type, int ndigits, bool sign_required, bool thousands, double *the_value);
289 static int fmt_fractional_value (FORMAT_DIGIT type, int ndigits, double *the_value);
290 static int fmt_fractional_digits (FORMAT_DIGIT type, int ndigits, double *the_value, int *nfound);
291 #if defined (ENABLE_UNUSED_FUNCTION)
292 static void fmt_add_thousands (ADJ_ARRAY * string, int *position);
293 static void fmt_drop_thousands (ADJ_ARRAY * string, int *position);
294 static void fmt_add_integral (ADJ_ARRAY *, int *, int, FORMAT_DIGIT, FMT_LEX_MODE);
295 static void fmt_drop_integral (ADJ_ARRAY * string, int *pos, int ndigits, FMT_LEX_MODE mode);
296 static int fmt_decimals (ADJ_ARRAY * string);
297 static int fmt_fraction_position (ADJ_ARRAY * string, int start);
298 static bool fmt_add_decimal (ADJ_ARRAY * string, int *position);
299 static void fmt_add_fractional (ADJ_ARRAY *, int *, int, FORMAT_DIGIT);
300 static void fmt_drop_fractional (ADJ_ARRAY *, int *, int);
301 static void fmt_add_currency (ADJ_ARRAY *, int *, MONETARY_FORMAT *);
302 #endif /* ENABLE_UNUSED_FUNCTION */
303 static void cnvutil_cleanup (void);
304 
305 static const char *fmt_date_string (const DB_DATE * the_date, const char *descriptor);
306 #if defined (ENABLE_UNUSED_FUNCTION)
307 static const char *fmt_year_string (int year, const char *descriptor);
308 static const char *fmt_month_string (int month, const char *descriptor);
309 static int fmt_month_value (const char *descriptor, int *the_month);
310 static const char *fmt_monthday_string (int day, const char *descriptor);
311 static int fmt_monthday_value (const char *descriptor, int *the_day);
312 static const char *fmt_weekday_string (int weekday, const char *descriptor);
313 static int fmt_year_value (const char *descriptor, int *the_year);
314 static int fmt_weekday_value (const char *descriptor, int *the_day);
315 static DB_DATE fmt_weekday_date (int month, int day, int year, int weekday);
316 #endif
317 static int fmt_date_value (const char *descriptor, int *the_month, int *the_day, int *the_year);
318 
319 static const char *fmt_time_string (const DB_TIME * the_time, const char *descriptor);
320 #if defined (ENABLE_UNUSED_FUNCTION)
321 static const char *fmt_hour_string (const DB_TIME * the_time, const char *descriptor);
322 static int fmt_hour_value (const char *descriptor, int *the_hour);
323 static const char *fmt_minute_string (const DB_TIME * the_time, const char *descriptor);
324 static const char *fmt_second_string (const DB_TIME * the_time, const char *descriptor);
325 #endif
326 static int fmt_time_value (const char *descriptor, int *the_hour, int *the_min, int *the_sec);
327 static const char *fmt_timestamp_string (const DB_TIMESTAMP * the_timestamp, const char *descriptor);
328 static int fmt_timestamp_value (const char *descriptor, int *the_month, int *the_day, int *the_year, int *the_hour,
329  int *the_min, int *the_sec);
330 static const FMT_TOKEN *tfmt_new (const char *format);
331 
332 static bool ffmt_valid_char (FMT_TOKEN * token);
333 static void ffmt_new (FLOAT_FORMAT * ffmt, const char *format);
334 static const char *ffmt_value (FLOAT_FORMAT * ffmt, const char *string, double *the_double);
335 #if defined (ENABLE_UNUSED_FUNCTION)
336 static int ffmt_print (FLOAT_FORMAT * ffmt, double the_double, char *string, int max_size);
337 static int mfmt_print (MONETARY_FORMAT * mfmt, double the_double, char *string, int max_size);
338 #endif
339 static bool mfmt_valid_char (FMT_TOKEN * token);
340 static void mfmt_new (MONETARY_FORMAT * mfmt, const char *format, DB_CURRENCY currency_type);
341 static const char *mfmt_value (MONETARY_FORMAT * mfmt, const char *string, double *the_double);
342 
343 static bool ifmt_valid_char (FMT_TOKEN * token);
344 static void ifmt_new (INTEGER_FORMAT * ifmt, const char *format);
345 static const char *ifmt_value (INTEGER_FORMAT * ifmt, const char *string, int *the_integer);
346 static const char *bifmt_value (INTEGER_FORMAT * bifmt, const char *string, DB_BIGINT * the_bigint);
347 static const char *ifmt_numeric_value (INTEGER_FORMAT * ifmt, const char *string, int *the_integer);
348 static const char *bifmt_numeric_value (INTEGER_FORMAT * ifmt, const char *string, DB_BIGINT * the_bigint);
349 #if defined (ENABLE_UNUSED_FUNCTION)
350 static int ifmt_text_numeric (INTEGER_FORMAT * ifmt, ADJ_ARRAY * string);
351 static const char *ifmt_text_value (INTEGER_FORMAT * ifmt, const char *string, int *the_integer);
352 static const char *bifmt_text_value (INTEGER_FORMAT * ifmt, const char *string, DB_BIGINT * the_bigint);
353 static int ifmt_print (INTEGER_FORMAT * ifmt, DB_BIGINT the_bigint, char *string, int max_size);
354 static int ifmt_text_print (INTEGER_FORMAT * ifmt, DB_BIGINT the_bigint, char *string, int max_size);
355 static void ifmt_numeric_text (INTEGER_FORMAT * ifmt, ADJ_ARRAY * numeric_string);
356 static int ifmt_numeric_print (INTEGER_FORMAT * ifmt, DB_BIGINT the_bigint, char *string, int max_size);
357 #endif
358 static bool bfmt_valid_char (FMT_TOKEN * token);
359 static void bfmt_new (BIT_STRING_FORMAT * bfmt, const char *format);
360 static const char *bfmt_value (BIT_STRING_FORMAT bfmt, const char *string, DB_VALUE * the_db_bit);
361 static int bfmt_print (BIT_STRING_FORMAT * bfmt, const DB_VALUE * the_db_bit, char *string, int max_size);
362 
363 static int num_fmt_print (FLOAT_FORMAT * ffmt, const DB_VALUE * the_numeric, char *string, int max_size);
364 #if defined (ENABLE_UNUSED_FUNCTION)
365 static const char *num_fmt_value (FLOAT_FORMAT * ffmt, const char *string, DB_VALUE * the_numeric);
366 static int nfmt_integral_value (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands,
367  char *the_value);
368 static int nfmt_integral_digits (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands,
369  char *the_value, int *nfound);
370 static int nfmt_fractional_digits (FORMAT_DIGIT digit_type, int ndigits, char *the_value, int *nfound);
371 static int nfmt_fractional_value (FORMAT_DIGIT digit_type, int ndigits, char *the_value);
372 #endif
373 static int fmt_max_digits;
374 
375 #if defined (SERVER_MODE)
376 static ADJ_ARRAY *cnv_get_thread_local_adj_buffer (int idx);
377 static void cnv_set_thread_local_adj_buffer (int idx, ADJ_ARRAY * buffer_p);
378 #endif // SERVER_MODE
379 
380 /* Internal buffers.
381  *
382  * These were formerly declared as static within the functions that used
383  * them. They were moved outside and placed together so we know what
384  * they are all so they can be freed by cnvutil_cleanup() when we don't
385  * need them anymore. This was important on the PC since we like to
386  * clean up after ourselves after the database connection is shut down.
387  *
388  * Its not clear if each of the functions needs to have its own buffer or
389  * if we can just share one of these in all places.
390  */
391 
392 /* used by cnv_wcs */
393 #if !defined(SERVER_MODE)
395 
396 /* used by cnv_get_string_buffer */
398 
399 /* used by cnv_get_value_string_buffer */
401 #endif
402 
403 static const char *kor_weekday_names[] = {
404  "(\xc0\xcf)", /* il */
405  "(\xbf\xf9)", /* wol */
406  "(\xc8\xad)", /* hwa */
407  "(\xbc\xf6)", /* su */
408  "(\xb8\xf1)", /* mok */
409  "(\xb1\xdd)", /* geum */
410  "(\xc5\xe4)" /* to */
411 };
412 
413 static const char *kr_short_month_names[] = {
414  "1\xbf\xf9", /* 1 wol */
415  "2\xbf\xf9", /* 2 wol */
416  "3\xbf\xf9", /* 3 wol */
417  "4\xbf\xf9", /* 4 wol */
418  "5\xbf\xf9", /* 5 wol */
419  "6\xbf\xf9", /* 6 wol */
420  "7\xbf\xf9", /* 7 wol */
421  "8\xbf\xf9", /* 8 wol */
422  "9\xbf\xf9", /* 9 wol */
423  "10\xbf\xf9", /* 10 wol */
424  "11\xbf\xf9", /* 11 wol */
425  "12\xbf\xf9" /* 12 wol */
426 };
427 
428 static const char *kr_long_month_names[] = {
429  "1\xbf\xf9", /* 1 wol */
430  "2\xbf\xf9", /* 2 wol */
431  "3\xbf\xf9", /* 3 wol */
432  "4\xbf\xf9", /* 4 wol */
433  "5\xbf\xf9", /* 5 wol */
434  "6\xbf\xf9", /* 6 wol */
435  "7\xbf\xf9", /* 7 wol */
436  "8\xbf\xf9", /* 8 wol */
437  "9\xbf\xf9", /* 9 wol */
438  "10\xbf\xf9", /* 10 wol */
439  "11\xbf\xf9", /* 11 wol */
440  "12\xbf\xf9" /* 12 wol */
441 };
442 
443 static const char *eng_short_month_names[] = {
444  "Jan",
445  "Feb",
446  "Mar",
447  "Apr",
448  "May",
449  "Jun",
450  "Jul",
451  "Aug",
452  "Sep",
453  "Oct",
454  "Nov",
455  "Dec"
456 };
457 
458 static const char *eng_long_month_names[] = {
459  "January",
460  "February",
461  "March",
462  "April",
463  "May",
464  "June",
465  "July",
466  "August",
467  "September",
468  "October",
469  "November",
470  "December"
471 };
472 
473 static const char *eng_short_weekday_names[] = {
474  "Sun",
475  "Mon",
476  "Tue",
477  "Wed",
478  "Thu",
479  "Fri",
480  "Sat"
481 };
482 
483 static const char *eng_long_weekday_names[] = {
484  "Sunday",
485  "Monday",
486  "Tuesday",
487  "Wednesday",
488  "Thursday",
489  "Friday",
490  "Saturday"
491 };
492 
493 /*
494  * us_date_string() - Return a string representing the given date in the US
495  * date format.
496  * return:
497  * month(in) :
498  * day(in) :
499  * year(in) :
500  */
501 static const char *
502 us_date_string (int month, int day, int year)
503 {
504  static char date_string[FMT_MAX_DATE_STRING * MB_LEN_MAX + 1];
505 
506  sprintf (date_string, "%d/%d/%d", month, day, year);
507  assert (strlen (date_string) < (int) sizeof (date_string));
508 
509  return date_string;
510 }
511 
512 /*
513  * us_date_value() - Scan tokens and parse a date value in the US date format.
514  * If a valid value can't be found, then return an error condition.
515  * otherwise, set the_month, the_day, and the_year to the value found.
516  * return:
517  * the_month(out) :
518  * the_day(out) :
519  * the_year(out) :
520  */
521 static int
522 us_date_value (int *the_month, int *the_day, int *the_year)
523 {
524  bool bad_value = false;
525  int error = 0;
526  FMT_TOKEN token;
527 
528  do
529  {
530  FMT_TOKEN_TYPE type;
531 
532  type = cnv_fmt_lex (&token);
533  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY || type == FT_TIME_DIGITS_0)
534  || (*the_month = atoi (token.text)) > 12 || *the_month < 1;
535  if (bad_value)
536  {
537  break;
538  }
539 
540  bad_value = cnv_fmt_lex (&token) != FT_DATE_SEPARATOR;
541  if (bad_value)
542  {
543  break;
544  }
545 
546  type = cnv_fmt_lex (&token);
547  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY || type == FT_TIME_DIGITS_0)
548  || (*the_day = atoi (token.text)) > 31 || *the_day < 1;
549  if (bad_value)
550  {
551  break;
552  }
553 
554  bad_value = cnv_fmt_lex (&token) != FT_DATE_SEPARATOR;
555  if (bad_value)
556  {
557  break;
558  }
559 
560  type = cnv_fmt_lex (&token);
561  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY);
562  if (bad_value)
563  {
564  break;
565  }
566 
567  *the_year = atoi (token.text);
568  /* Year 0 doesn't exist! */
569  bad_value = type == FT_TIME_DIGITS_ANY && *the_year == 0;
570  if (bad_value)
571  {
572  break;
573  }
574 
575  if (type != FT_TIME_DIGITS_ANY)
576  {
577  /* Abbreviated year: add current century. */
578  struct tm tm_val, *today;
579  time_t now = time (NULL);
580  today = localtime_r (&now, &tm_val);
581 
582  if (today != NULL)
583  {
584  *the_year += ((today->tm_year + 1900) / 100) * 100;
585  }
586  else
587  {
588  bad_value = true;
589  }
590  }
591 
592  }
593  while (0);
594 
595  if (bad_value)
596  {
597  error = CNV_ERR_BAD_DATE;
598  co_signal (error, CNV_ER_FMT_BAD_DATE, "x");
599  }
600 
601  return error;
602 }
603 
604 #if defined(ENABLE_UNUSED_FUNCTION)
605 /*
606  * us_alt_date_string() - Return a string representing the given date in the
607  * US alternate date format.
608  * return:
609  * month(in) :
610  * day(in) :
611  * year(in) :
612  */
613 static const char *
614 us_alt_date_string (int month, int day, int year)
615 {
616  return us_date_string (month, day, year);
617 }
618 
619 /*
620  * us_alt_date_value() - Scan tokens and parse a date value in the US
621  * alternate date format. If a valid value can't be found, then
622  * return an error condition.
623  * otherwise, set the_month, the_day, and the_year to the value found.
624  * return:
625  * the_month(out) :
626  * the_day(out) :
627  * the_year(out) :
628  */
629 static int
630 us_alt_date_value (int *the_month, int *the_day, int *the_year)
631 {
632  return us_date_value (the_month, the_day, the_year);
633 }
634 #endif
635 
636 /*
637  * us_time_string() - Return a string representing the given time in the US
638  * time format.
639  * return:
640  * the_time(in) :
641  */
642 static const char *
643 us_time_string (const DB_TIME * the_time)
644 {
645  static char time_string[FMT_MAX_TIME_STRING * MB_LEN_MAX + 1];
646  int hour, min, sec;
647 
648  db_time_decode ((DB_TIME *) the_time, &hour, &min, &sec);
649 
650  sprintf (time_string, "%d:%02d:%02d %s", hour % 12 ? hour % 12 : 12, min, sec, local_am_pm_string (the_time));
651  assert (strlen (time_string) < (int) sizeof (time_string));
652 
653  return time_string;
654 }
655 
656 /*
657  * us_time_value() - Scan tokens and parse a time value in the US time format.
658  * If a valid value can't be found, then return an error condition.
659  * otherwise, set the_hour, the_min, and the_sec to the value found.
660  * return:
661  * the_hour(out) :
662  * the_min(out) :
663  * the_sec(out) :
664  */
665 static int
666 us_time_value (int *the_hour, int *the_min, int *the_sec)
667 {
668  bool bad_value = false;
669  int error = 0;
670  FMT_TOKEN token;
671  FMT_TOKEN_TYPE type;
672  bool pm;
673 
674  do
675  {
676  type = cnv_fmt_lex (&token);
677  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY || type == FT_TIME_DIGITS_0)
678  || (*the_hour = atoi (token.text)) > 23 || *the_hour < 0;
679  if (bad_value)
680  {
681  break;
682  }
683 
684  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
685  if (bad_value)
686  {
687  break;
688  }
689 
690  error = fmt_minute_value ("M", the_min);
691  if (error)
692  {
693  break;
694  }
695 
696  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
697  if (bad_value)
698  {
699  break;
700  }
701 
702  error = fmt_second_value ("S", the_sec);
703  if (error)
704  {
705  break;
706  }
707 
708  /* Skip blank "pattern" character. */
709  if (strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE)) == 0)
710  {
712  }
713  else
714  {
716  }
717 
718  /* we used to use local_am_pm_value() here, but it wasn't flexible enough to handle 24 hour time strings (no "AM"
719  * or "PM" designator). */
720 
721  type = cnv_fmt_lex (&token);
722 
723  if (type == FT_NONE)
724  {
725  /* do nothing to hour, no "AM" or "PM" follows */
726  ;
727  }
728  else if (type == FT_AM_PM && *the_hour >= 1 && *the_hour <= 12)
729  {
730  pm = token.value;
731  /* convert 12 to 0 hour before adding 12 for PM values */
732  *the_hour %= 12;
733  if (pm)
734  {
735  *the_hour += 12;
736  }
737  }
738  else
739  {
740  error = CNV_ERR_BAD_AM_PM;
741  co_signal (error, CNV_ER_FMT_BAD_AM_PM, "p");
742  break;
743  }
744 
745  }
746  while (0);
747 
748  if (bad_value)
749  {
750  error = CNV_ERR_BAD_TIME;
751  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
752  }
753 
754  return error;
755 }
756 
757 #if defined (ENABLE_UNUSED_FUNCTION)
758 /*
759  * us_mtime_string() - Return a string representing the given time in the US
760  * time format.
761  * return:
762  * the_time(in) :
763  */
764 static const char *
765 us_mtime_string (int hour, int minute, int second, int millisecond)
766 {
767  static char time_string[FMT_MAX_MTIME_STRING * MB_LEN_MAX + 1];
768 
769  sprintf (time_string, "%d:%02d:%02d.%03d %s", hour % 12 ? hour % 12 : 12, minute, second, millisecond,
770  hour > 12 ? local_pm () : local_am ());
771  assert (strlen (time_string) < sizeof time_string);
772 
773  return time_string;
774 }
775 
776 /*
777  * us_mtime_value() - Scan tokens and parse a time value in the US time format.
778  * If a valid value can't be found, then return an error condition.
779  * otherwise, set the_hour, the_min, and the_sec to the value found.
780  * return:
781  * the_hour(out) :
782  * the_min(out) :
783  * the_sec(out) :
784  */
785 static int
786 us_mtime_value (int *the_hour, int *the_min, int *the_sec, int *the_msec)
787 {
788  bool bad_value = false;
789  int error = 0;
790  FMT_TOKEN token;
791  FMT_TOKEN_TYPE type;
792  bool pm;
793 
794  type = cnv_fmt_lex (&token);
795  if (!(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY || type == FT_TIME_DIGITS_0)
796  || (*the_hour = atoi (token.text)) > 23 || *the_hour < 0)
797  {
798  error = CNV_ERR_BAD_TIME;
799  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
800  goto end;
801  }
802 
803  if (cnv_fmt_lex (&token) != FT_TIME_SEPARATOR)
804  {
805  error = CNV_ERR_BAD_TIME;
806  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
807  goto end;
808  }
809 
810  error = fmt_minute_value ("M", the_min);
811  if (error)
812  {
813  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
814  goto end;
815  }
816 
817  if (cnv_fmt_lex (&token) != FT_TIME_SEPARATOR)
818  {
819  error = CNV_ERR_BAD_TIME;
820  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
821  goto end;
822  }
823 
824  error = fmt_second_value ("S", the_sec);
825  if (error)
826  {
827  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
828  goto end;
829  }
830 
831  /* TODO: DATETIME MILLISECOND SEPARATOR ?? */
832  if (cnv_fmt_lex (&token) != FT_TIME_SEPARATOR)
833  {
834  *the_msec = 0;
835  }
836  else
837  {
838  error = fmt_millisecond_value ("MS", the_msec);
839  if (error)
840  {
841  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
842  goto end;
843  }
844  }
845 
846  /* Skip blank "pattern" character. */
847  if (strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE)) == 0)
848  {
850  }
851  else
852  {
854  }
855 
856  /* we used to use local_am_pm_value() here, but it wasn't flexible enough to handle 24 hour time strings (no "AM" or
857  * "PM" designator). */
858 
859  type = cnv_fmt_lex (&token);
860  if (type == FT_NONE)
861  {
862  /* do nothing to hour, no "AM" or "PM" follows */
863  ;
864  }
865  else if (type == FT_AM_PM && *the_hour >= 1 && *the_hour <= 12)
866  {
867  pm = token.value;
868  /* convert 12 to 0 hour before adding 12 for PM values */
869  *the_hour %= 12;
870  if (pm)
871  {
872  *the_hour += 12;
873  }
874  }
875  else
876  {
877  error = CNV_ERR_BAD_AM_PM;
878  co_signal (error, CNV_ER_FMT_BAD_AM_PM, "p");
879  }
880 
881 end:
882  return error;
883 }
884 
885 /*
886  * us_timestamp_string() - Return a string representing the given timestamp in
887  * the US timestamp format.
888  * return:
889  * the_timestamp(in) :
890  */
891 static const char *
892 us_timestamp_string (const DB_TIMESTAMP * the_timestamp)
893 {
894  static char timestamp_string[FMT_MAX_TIMESTAMP_STRING * MB_LEN_MAX + 1];
895 
896  DB_DATE the_date;
897  DB_TIME the_time;
898  int month;
899  int day;
900  int year;
901 
902  db_timestamp_decode_ses ((DB_TIMESTAMP *) the_timestamp, &the_date, &the_time);
903  db_date_decode (&the_date, &month, &day, &year);
904 
905  sprintf (timestamp_string, "%s %s", us_date_string (month, day, year), us_time_string (&the_time));
906  assert (strlen (timestamp_string) < sizeof timestamp_string);
907 
908  return timestamp_string;
909 }
910 
911 /*
912  * us_timestamp_value() - Scan tokens and parse timestamp value in the US
913  * timestamp format. If a valid value can't be found, then return an
914  * error condition. otherwise, set the_day, the_month, the_year,
915  * the_hour (0-23), the_min, and the_sec to the value found.
916  * return:
917  * the_month(out) :
918  * the_day(out) :
919  * the_year(out) :
920  * the_hour(out) :
921  * the_min(out) :
922  * the_sec(out) :
923  */
924 static int
925 us_timestamp_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec)
926 {
927  bool bad_value = false;
928  int error = 0;
929 
930  do
931  {
932  error = us_date_value (the_month, the_day, the_year);
933  if (error)
934  {
935  break;
936  }
937 
938  /* Skip blank "pattern" character. */
939  bad_value = strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE));
940  if (bad_value)
941  {
942  break;
943  }
945 
946  error = us_time_value (the_hour, the_min, the_sec);
947 
948  }
949  while (0);
950 
951  if (bad_value)
952  {
953  error = CNV_ERR_BAD_TIMESTAMP;
954  co_signal (error, CNV_ER_FMT_BAD_TIMESTAMP, "C");
955  }
956 
957  return error;
958 }
959 
960 /*
961  * us_datetime_string() - Return a string representing the given datetime in
962  * the US datetime format.
963  * return:
964  * the_timestamp(in) :
965  */
966 static const char *
967 us_datetime_string (const DB_DATETIME * the_datetime)
968 {
969  static char datetime_string[FMT_MAX_DATETIME_STRING * MB_LEN_MAX + 1];
970 
971  int month, day, year;
972  int hour, minute, second, millisecond;
973 
974  db_datetime_decode ((DB_DATETIME *) the_datetime, &month, &day, &year, &hour, &minute, &second, &millisecond);
975 
976  sprintf (datetime_string, "%s %s", us_date_string (month, day, year),
977  us_mtime_string (hour, minute, second, millisecond));
978 
979  return datetime_string;
980 }
981 
982 /*
983  * us_datetime_value() - Scan tokens and parse datetime value in the US
984  * datetime format. If a valid value can't be found, then return an
985  * error condition. otherwise, set the_day, the_month, the_year,
986  * the_hour (0-23), the_min, the_sec, and the_msec to the value found.
987  * return:
988  * the_month(out) :
989  * the_day(out) :
990  * the_year(out) :
991  * the_hour(out) :
992  * the_min(out) :
993  * the_sec(out) :
994  */
995 static int
996 us_datetime_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec,
997  int *the_msec)
998 {
999  bool bad_value = false;
1000  int error = 0;
1001 
1002  do
1003  {
1004  error = us_date_value (the_month, the_day, the_year);
1005  if (error)
1006  {
1007  break;
1008  }
1009 
1010  /* Skip blank "pattern" character. */
1011  bad_value = strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE));
1012  if (bad_value)
1013  {
1014  break;
1015  }
1017 
1018  error = us_mtime_value (the_hour, the_min, the_sec, the_msec);
1019 
1020  }
1021  while (0);
1022 
1023  if (bad_value)
1024  {
1025  error = CNV_ERR_BAD_DATETIME;
1026  co_signal (error, CNV_ER_FMT_BAD_DATETIME, "C");
1027  }
1028 
1029  return error;
1030 }
1031 
1032 /*
1033  * KR Zone Functions
1034  */
1035 
1036 /*
1037  * ko_euc_year_wc() -
1038  * return:
1039  */
1040 static wchar_t
1041 ko_euc_year_wc (void)
1042 {
1043  static wchar_t ko_euc_year = 0;
1044 
1045  if (!ko_euc_year)
1046  {
1047  mbtowc (&ko_euc_year, KOREAN_EUC_YEAR_SYMBOL, 1);
1048  }
1049 
1050  return ko_euc_year;
1051 }
1052 
1053 /*
1054  * ko_euc_month_wc() -
1055  * return:
1056  */
1057 static wchar_t
1058 ko_euc_month_wc (void)
1059 {
1060  static wchar_t ko_euc_month = 0;
1061 
1062  if (!ko_euc_month)
1063  {
1064  mbtowc (&ko_euc_month, KOREAN_EUC_MONTH_SYMBOL, 1);
1065  }
1066 
1067  return ko_euc_month;
1068 }
1069 
1070 /*
1071  * ko_euc_day_wc() -
1072  * return:
1073  */
1074 static wchar_t
1075 ko_euc_day_wc (void)
1076 {
1077  static wchar_t ko_euc_day = 0;
1078 
1079  if (!ko_euc_day)
1080  {
1081  mbtowc (&ko_euc_day, KOREAN_EUC_DAY_SYMBOL, 1);
1082  }
1083 
1084  return ko_euc_day;
1085 }
1086 #endif
1087 
1088 /*
1089  * ko_date_string() - Return a string representing the given date in the
1090  * Korean date format.
1091  * return:
1092  * month(in) :
1093  * day(in) :
1094  * year(in) :
1095  */
1096 static const char *
1097 ko_date_string (int month, int day, int year)
1098 {
1099  static char date_string[FMT_MAX_DATE_STRING * MB_LEN_MAX + 1];
1100 
1101  sprintf (date_string, "%04d/%02d/%02d", year, month, day);
1102  assert (strlen (date_string) < (int) sizeof (date_string));
1103 
1104  return date_string;
1105 }
1106 
1107 #if defined (ENABLE_UNUSED_FUNCTION)
1108 /*
1109  * ko_alt_date_string() - Return a string representing the given date in the
1110  * Korean date format.
1111  * return:
1112  * month(in) :
1113  * day(in) :
1114  * year(in) :
1115  */
1116 static const char *
1117 ko_alt_date_string (int month, int day, int year)
1118 {
1119  static char date_string[FMT_MAX_DATE_STRING * MB_LEN_MAX + 1];
1120 
1121  sprintf (date_string, "%04d%s%02d%s%02d%s", year, KOREAN_EUC_YEAR_SYMBOL, month, KOREAN_EUC_MONTH_SYMBOL, day,
1123  assert (strlen (date_string) < sizeof date_string);
1124 
1125  return date_string;
1126 }
1127 #endif
1128 
1129 /*
1130  * ko_date_value() - Scan tokens and parse a date value in the Korean date
1131  * format. If a valid value can't be found, then return an error condition.
1132  * otherwise, set the_year, the_month, and the_day to the value found.
1133  * return:
1134  * the_month(out) :
1135  * the_day(out) :
1136  * the_year(out) :
1137  */
1138 static int
1139 ko_date_value (int *the_month, int *the_day, int *the_year)
1140 {
1141  bool bad_value = false;
1142  int error = 0;
1143  FMT_TOKEN token;
1144 
1145  do
1146  {
1147  FMT_TOKEN_TYPE type;
1148 
1149  type = cnv_fmt_lex (&token);
1150  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY);
1151  if (bad_value)
1152  {
1153  break;
1154  }
1155 
1156  *the_year = atoi (token.text);
1157  /* Year 0 doesn't exist! */
1158  bad_value = type == FT_TIME_DIGITS_ANY && *the_year == 0;
1159  if (bad_value)
1160  {
1161  break;
1162  }
1163 
1164  if (type != FT_TIME_DIGITS_ANY)
1165  {
1166  /* Abbreviated year: add current century. */
1167  struct tm tm_val, *today;
1168  time_t now = time (NULL);
1169  today = localtime_r (&now, &tm_val);
1170 
1171  if (today != NULL)
1172  {
1173  *the_year += ((today->tm_year + 1900) / 100) * 100;
1174  }
1175  else
1176  {
1177  bad_value = true;
1178  break;
1179  }
1180  }
1181 
1182  bad_value = cnv_fmt_lex (&token) != FT_DATE_SEPARATOR;
1183  if (bad_value)
1184  {
1185  break;
1186  }
1187 
1188  type = cnv_fmt_lex (&token);
1189  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS_ANY
1190  || type == FT_TIME_DIGITS_BLANK) || (*the_month = atoi (token.text)) > 12 || *the_month < 1;
1191  if (bad_value)
1192  {
1193  break;
1194  }
1195 
1196  bad_value = cnv_fmt_lex (&token) != FT_DATE_SEPARATOR;
1197  if (bad_value)
1198  {
1199  break;
1200  }
1201 
1202  type = cnv_fmt_lex (&token);
1203  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS_ANY
1204  || type == FT_TIME_DIGITS_BLANK) || (*the_day = atoi (token.text)) > 31 || *the_day < 1;
1205  if (bad_value)
1206  {
1207  break;
1208  }
1209 
1210  }
1211  while (0);
1212 
1213  if (bad_value)
1214  {
1215  error = CNV_ERR_BAD_DATE;
1216  co_signal (error, CNV_ER_FMT_BAD_DATE, "x");
1217  }
1218 
1219  return error;
1220 }
1221 
1222 #if defined (ENABLE_UNUSED_FUNCTION)
1223 /*
1224  * ko_alt_date_value() - Scan tokens and parse a date value in the Korean
1225  * date format. If a valid value can't be found, then return an error
1226  * condition. otherwise, set the_year, the_month, and the_day to the value
1227  * found.
1228  * return:
1229  * the_month(out) :
1230  * the_day(out) :
1231  * the_year(out) :
1232  */
1233 static int
1234 ko_alt_date_value (int *the_month, int *the_day, int *the_year)
1235 {
1236  bool bad_value = false;
1237  int error = 0;
1238  FMT_TOKEN token;
1239 
1240  do
1241  {
1242  FMT_TOKEN_TYPE type;
1243 
1244  type = cnv_fmt_lex (&token);
1245  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY);
1246  if (bad_value)
1247  {
1248  break;
1249  }
1250 
1251  *the_year = atoi (token.text);
1252  /* Year 0 doesn't exist! */
1253  bad_value = type == FT_TIME_DIGITS_ANY && *the_year == 0;
1254  if (bad_value)
1255  {
1256  break;
1257  }
1258 
1259  if (type != FT_TIME_DIGITS_ANY)
1260  {
1261 
1262  /* Abbreviated year: add current century. */
1263  struct tm tm_val, *today;
1264  time_t now = time (NULL);
1265  today = localtime_r (&now, &tm_val);
1266 
1267  if (today != NULL)
1268  {
1269  *the_year += ((today->tm_year + 1900) / 100) * 100;
1270  }
1271  else
1272  {
1273  bad_value = true;
1274  break;
1275  }
1276  }
1277 
1278  type = cnv_fmt_lex (&token);
1279  bad_value = !(type == FT_LOCAL_DATE_SEPARATOR && token.text == intl_mbs_chr (token.text, ko_euc_year_wc ()));
1280  if (bad_value)
1281  {
1282  break;
1283  }
1284 
1285  type = cnv_fmt_lex (&token);
1286  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS_ANY
1287  || type == FT_TIME_DIGITS_BLANK) || (*the_month = atoi (token.text)) > 12 || *the_month < 1;
1288  if (bad_value)
1289  {
1290  break;
1291  }
1292 
1293  type = cnv_fmt_lex (&token);
1294  bad_value = !(type == FT_LOCAL_DATE_SEPARATOR && token.text == intl_mbs_chr (token.text, ko_euc_month_wc ()));
1295  if (bad_value)
1296  {
1297  break;
1298  }
1299 
1300  type = cnv_fmt_lex (&token);
1301  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS_ANY
1302  || type == FT_TIME_DIGITS_BLANK) || (*the_day = atoi (token.text)) > 31 || *the_day < 1;
1303  if (bad_value)
1304  {
1305  break;
1306  }
1307 
1308  type = cnv_fmt_lex (&token);
1309  bad_value = !(type == FT_LOCAL_DATE_SEPARATOR && token.text == intl_mbs_chr (token.text, ko_euc_day_wc ()));
1310  if (bad_value)
1311  {
1312  break;
1313  }
1314 
1315  }
1316  while (0);
1317 
1318  if (bad_value)
1319  {
1320  error = CNV_ERR_BAD_DATE;
1321  co_signal (error, CNV_ER_FMT_BAD_DATE, "E");
1322  }
1323 
1324  return error;
1325 }
1326 #endif
1327 
1328 /*
1329  * ko_time_string() - Return a string representing the given time in the
1330  * Korean time format.
1331  * return:
1332  * the_time(in) :
1333  */
1334 static const char *
1335 ko_time_string (const DB_TIME * the_time)
1336 {
1337  static char time_string[FMT_MAX_TIME_STRING * MB_LEN_MAX + 1];
1338  int hour, min, sec;
1339 
1340  db_time_decode ((DB_TIME *) the_time, &hour, &min, &sec);
1341 
1342  sprintf (time_string, "%s %d\xbd\xc3%02d\xba\xd0%02d\xc3\xca", /* ????/????/???? */
1343  local_am_pm_string (the_time), (hour % 12 ? hour % 12 : 12), min, sec);
1344  assert (strlen (time_string) < (int) sizeof (time_string));
1345 
1346  return time_string;
1347 }
1348 
1349 /*
1350  * ko_time_value() - Scan tokens and parse a time value in the Korean time
1351  * format. If a valid value can't be found, then return an error condition.
1352  * otherwise, set the_hour, the_min, and the_sec to the value found.
1353  * return:
1354  * the_hour(in) :
1355  * the_min(in) :
1356  * the_sec(in) :
1357  */
1358 static int
1359 ko_time_value (int *the_hour, int *the_min, int *the_sec)
1360 {
1361  bool bad_value = false;
1362  int error = 0;
1363  FMT_TOKEN token;
1364  FMT_TOKEN_TYPE type;
1365  bool pm;
1366 
1367  do
1368  {
1369  error = local_am_pm_value (&pm); /* ????????/???????? parsing */
1370  if (error)
1371  {
1372  break;
1373  }
1374 
1375  *the_hour %= 12;
1376  if (pm)
1377  {
1378  *the_hour += 12;
1379  }
1380  /* Skip blank "pattern" character. */
1381  while (!strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE)))
1383 
1384  type = cnv_fmt_lex (&token);
1385  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_BLANK || type == FT_TIME_DIGITS_0
1386  || type == FT_TIME_DIGITS_ANY) || (*the_hour = atoi (token.text)) > 12 || *the_hour < 1;
1387  if (bad_value)
1388  {
1389  break;
1390  }
1391 
1392  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
1393  if (bad_value)
1394  {
1395  break;
1396  }
1397 
1398  error = fmt_minute_value ("M", the_min);
1399  if (error)
1400  {
1401  break;
1402  }
1403 
1404  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
1405  if (bad_value)
1406  {
1407  break;
1408  }
1409 
1410  error = fmt_second_value ("S", the_sec);
1411  if (error)
1412  {
1413  break;
1414  }
1415 
1416  }
1417  while (0);
1418 
1419  if (bad_value)
1420  {
1421  error = CNV_ERR_BAD_TIME;
1422  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
1423  }
1424 
1425  return error;
1426 }
1427 
1428 #if defined(ENABLE_UNUSED_FUNCTION)
1429 /*
1430  * ko_mtime_string() - Return a string representing the given time in the
1431  * Korean time format.
1432  * return:
1433  * hour(in) :
1434  * minute(in) :
1435  * millisecond(in) :
1436  * millisecond(in) :
1437  */
1438 static const char *
1439 ko_mtime_string (int hour, int minute, int second, int millisecond)
1440 {
1441  static char mtime_string[FMT_MAX_MTIME_STRING * MB_LEN_MAX + 1];
1442 
1443  sprintf (mtime_string, "%s %d\xbd\xc3%02d\xba\xd0%02d\xc3\xca.%03d", /* ????/????/???? */
1444  hour >= 12 ? local_pm () : local_am (), (hour % 12 ? hour % 12 : 12), minute, second, millisecond);
1445  assert (strlen (mtime_string) < sizeof (mtime_string));
1446 
1447  return mtime_string;
1448 }
1449 
1450 /*
1451  * ko_mtime_value() - Scan tokens and parse a time value in the Korean time
1452  * format. If a valid value can't be found, then return an error condition.
1453  * otherwise, set the_hour, the_min, the_sec and the_msec to the value found.
1454  * return:
1455  * the_hour(out) :
1456  * the_min(out) :
1457  * the_sec(out) :
1458  * the_msec(out) :
1459  */
1460 static int
1461 ko_mtime_value (int *the_hour, int *the_min, int *the_sec, int *the_msec)
1462 {
1463  bool bad_value = false;
1464  int error = 0;
1465  FMT_TOKEN token;
1466  FMT_TOKEN_TYPE type;
1467  bool pm;
1468 
1469  do
1470  {
1471  error = local_am_pm_value (&pm); /* ????????/???????? parsing */
1472  if (error)
1473  {
1474  break;
1475  }
1476 
1477  *the_hour %= 12;
1478  if (pm)
1479  {
1480  *the_hour += 12;
1481  }
1482  /* Skip blank "pattern" character. */
1483  while (!strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE)))
1485 
1486  type = cnv_fmt_lex (&token);
1487  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_BLANK || type == FT_TIME_DIGITS_0
1488  || type == FT_TIME_DIGITS_ANY) || (*the_hour = atoi (token.text)) > 12 || *the_hour < 1;
1489  if (bad_value)
1490  {
1491  break;
1492  }
1493 
1494  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
1495  if (bad_value)
1496  {
1497  break;
1498  }
1499 
1500  error = fmt_minute_value ("M", the_min);
1501  if (error)
1502  {
1503  break;
1504  }
1505 
1506  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
1507  if (bad_value)
1508  {
1509  break;
1510  }
1511 
1512  error = fmt_second_value ("S", the_sec);
1513  if (error)
1514  {
1515  break;
1516  }
1517 
1518  }
1519  while (0);
1520 
1521  if (bad_value)
1522  {
1523  error = CNV_ERR_BAD_TIME;
1524  co_signal (error, CNV_ER_FMT_BAD_TIME, "X");
1525  }
1526 
1527  return error;
1528 }
1529 
1530 /*
1531  * ko_timestamp_string() - Return a string representing the given timestamp in
1532  * the Korean timestamp format.
1533  * return:
1534  * the_timestamp(in) :
1535  */
1536 static const char *
1537 ko_timestamp_string (const DB_TIMESTAMP * the_timestamp)
1538 {
1539  static char timestamp_string[FMT_MAX_TIMESTAMP_STRING * MB_LEN_MAX + 1];
1540 
1541  DB_DATE the_date;
1542  DB_TIME the_time;
1543  int month;
1544  int day;
1545  int year;
1546 
1547  db_timestamp_decode_ses ((DB_TIMESTAMP *) the_timestamp, &the_date, &the_time);
1548  db_date_decode (&the_date, &month, &day, &year);
1549 
1550  sprintf (timestamp_string, "%s %s", ko_date_string (month, day, year), ko_time_string (&the_time));
1551  assert (strlen (timestamp_string) < sizeof timestamp_string);
1552 
1553  return timestamp_string;
1554 }
1555 
1556 /*
1557  * ko_timestamp_value() - Scan tokens and parse timestamp value in the Korean
1558  * timestamp format. If a valid value can't be found, then return an error
1559  * condition.
1560  * otherwise, set the_year, the_month, the_day, the_hour (0-23),
1561  * the_min, and the_sec to the value found.
1562  * return:
1563  * the_month(out) :
1564  * the_day(out) :
1565  * the_year(out) :
1566  * the_hour(out) :
1567  * the_min(out) :
1568  * the_sec(out) :
1569  */
1570 static int
1571 ko_timestamp_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec)
1572 {
1573  bool bad_value = false;
1574  int error = 0;
1575 
1576  do
1577  {
1578  error = ko_date_value (the_month, the_day, the_year);
1579  if (error)
1580  {
1581  break;
1582  }
1583 
1584  /* Skip blank "pattern" character. */
1585  while (!strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE)))
1586  {
1588  }
1589 
1590  error = ko_time_value (the_hour, the_min, the_sec);
1591 
1592  }
1593  while (0);
1594 
1595  if (bad_value)
1596  {
1597  error = CNV_ERR_BAD_TIMESTAMP;
1598  co_signal (error, CNV_ER_FMT_BAD_TIMESTAMP, "C");
1599  }
1600 
1601  return error;
1602 }
1603 
1604 /*
1605  * ko_datetime_string() - Return a string representing the given datetime in
1606  * the Korean datetime format.
1607  * return:
1608  * the_timestamp(in) :
1609  */
1610 static const char *
1611 ko_datetime_string (const DB_DATETIME * the_datetime)
1612 {
1613  static char datetime_string[FMT_MAX_TIMESTAMP_STRING * MB_LEN_MAX + 1];
1614 
1615  int month, day, year;
1616  int hour, minute, second, millisecond;
1617 
1618  db_datetime_decode ((DB_DATETIME *) the_datetime, &month, &day, &year, &hour, &minute, &second, &millisecond);
1619 
1620  sprintf (datetime_string, "%s %s", ko_date_string (month, day, year),
1621  ko_mtime_string (hour, minute, second, millisecond));
1622  assert (strlen (datetime_string) < sizeof (datetime_string));
1623 
1624  return datetime_string;
1625 }
1626 
1627 /*
1628  * ko_datetime_value() - Scan tokens and parse datetime value in the Korean
1629  * datetime format. If a valid value can't be found, then return an error
1630  * condition.
1631  * otherwise, set the_year, the_month, the_day, the_hour (0-23),
1632  * the_min, the_sec and the_msec to the value found.
1633  * return:
1634  * the_month(out) :
1635  * the_day(out) :
1636  * the_year(out) :
1637  * the_hour(out) :
1638  * the_min(out) :
1639  * the_sec(out) :
1640  */
1641 static int
1642 ko_datetime_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec,
1643  int *the_msec)
1644 {
1645  bool bad_value = false;
1646  int error = 0;
1647 
1648  do
1649  {
1650  error = ko_date_value (the_month, the_day, the_year);
1651  if (error)
1652  {
1653  break;
1654  }
1655 
1656  /* Skip blank "pattern" character. */
1657  while (!strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE)))
1658  {
1660  }
1661 
1662  error = ko_time_value (the_hour, the_min, the_sec);
1663 
1664  }
1665  while (0);
1666 
1667  if (bad_value)
1668  {
1669  error = CNV_ERR_BAD_TIMESTAMP;
1670  co_signal (error, CNV_ER_FMT_BAD_TIMESTAMP, "C");
1671  }
1672 
1673  return error;
1674 }
1675 #endif
1676 
1677 /*
1678  * Locale-Dependent Functions
1679  */
1680 
1681 /*
1682  * local_grouping() - Return digit grouping array for the current locale.
1683  * See localeconv() for a definition of array contents.
1684  * return:
1685  */
1686 const char *
1688 {
1689  char *local_value = localeconv ()->grouping;
1690 
1691  return strlen (local_value) ? (const char *) local_value : "\3";
1692 }
1693 
1694 /*
1695  * local_thousands() - Returns thousands separator for current locale.
1696  * return:
1697  */
1698 const char *
1700 {
1701  char *local_value = localeconv ()->thousands_sep;
1702 
1703  return strlen (local_value) ? (const char *) local_value : ",";
1704 }
1705 
1706 /*
1707  * local_decimal() - Return decimal separator for current locale.
1708  * return:
1709  */
1710 const char *
1712 {
1713  char *local_value = localeconv ()->decimal_point;
1714 
1715  return strlen (local_value) ? (const char *) local_value : ".";
1716 }
1717 
1718 /*
1719  * local_am() - Return AM affix for current locale.
1720  * return:
1721  * note : nl_langinfo() not implemented. Must fix to support other locales.
1722  * local_value = nl_langinfo(AM_STR);
1723  */
1724 static const char *
1725 local_am (void)
1726 {
1727  const char *local_value;
1728 
1729  switch (intl_zone (LC_TIME))
1730  {
1731  case INTL_ZONE_US:
1732  {
1733  local_value = "am";
1734  break;
1735  }
1736  case INTL_ZONE_KR:
1737  {
1738  local_value = "\xbf\xc0\xc0\xfc"; /* ???????? */
1739  break;
1740  }
1741  default:
1742  {
1743  assert (!"Zone not implemented!");
1744  local_value = "";
1745  break;
1746  }
1747  }
1748 
1749  return local_value;
1750 }
1751 
1752 /*
1753  * local_pm() - Return PM affix for current locale.
1754  * return:
1755  *
1756  * note : nl_langinfo() not implemented. Must fix to support other locales.
1757  * local_value = nl_langinfo( PM_STR);
1758  */
1759 static const char *
1760 local_pm (void)
1761 {
1762  const char *local_value;
1763 
1764  switch (intl_zone (LC_TIME))
1765  {
1766  case INTL_ZONE_US:
1767  {
1768  local_value = "pm";
1769  break;
1770  }
1771  case INTL_ZONE_KR:
1772  {
1773  local_value = "\xbf\xc0\xc8\xc4"; /* ???????? */
1774  break;
1775  }
1776  default:
1777  {
1778  assert (!"Zone not implemented!");
1779  local_value = "";
1780  break;
1781  }
1782  }
1783 
1784  return local_value;
1785 }
1786 
1787 #if defined (ENABLE_UNUSED_FUNCTION)
1788 /*
1789  * local_short_month_name() - Return the short month name for the given
1790  * month number (0-11)
1791  * return:
1792  * month(in) :
1793  */
1794 static const char *
1795 local_short_month_name (int month)
1796 {
1797  const char *month_name;
1798 
1799  assert (month >= 0 && month <= 11);
1800 
1801  switch (intl_zone (LC_TIME))
1802  {
1803  case INTL_ZONE_US:
1804  {
1805  month_name = eng_short_month_names[month];
1806  break;
1807  }
1808  case INTL_ZONE_KR:
1809  {
1810  month_name = kr_short_month_names[month];
1811  break;
1812  }
1813  default:
1814  {
1815  assert (!"Zone not implemented!");
1816  month_name = "";
1817  break;
1818  }
1819  }
1820 
1821  return month_name;
1822 }
1823 
1824 /*
1825  * local_long_month_name() - Return the long month name for the given
1826  * month number (0-11)
1827  * return:
1828  * month(in) :
1829  */
1830 static const char *
1831 local_long_month_name (int month)
1832 {
1833  const char *month_name;
1834 
1835  assert (month >= 0 && month <= 11);
1836 
1837  switch (intl_zone (LC_TIME))
1838  {
1839  case INTL_ZONE_US:
1840  {
1841  month_name = eng_long_month_names[month];
1842  break;
1843  }
1844  case INTL_ZONE_KR:
1845  {
1846  month_name = kr_long_month_names[month];
1847  break;
1848  }
1849  default:
1850  {
1851  assert (!"Zone not implemented!");
1852  month_name = "";
1853  break;
1854  }
1855  }
1856 
1857  return month_name;
1858 }
1859 
1860 /*
1861  * local_short_weekday_name() - Return the short weekday name for the given
1862  * weekday number (0-6)
1863  * return:
1864  * weekday(in) :
1865  */
1866 static const char *
1867 local_short_weekday_name (int weekday)
1868 {
1869  const char *weekday_name;
1870 
1871  assert (weekday >= 0 && weekday <= 6);
1872 
1873  switch (intl_zone (LC_TIME))
1874  {
1875  case INTL_ZONE_US:
1876  {
1877  weekday_name = eng_short_weekday_names[weekday];
1878  break;
1879  }
1880  case INTL_ZONE_KR:
1881  {
1882  weekday_name = kor_weekday_names[weekday];
1883  break;
1884  }
1885  default:
1886  {
1887  assert (!"Zone not implemented!");
1888  weekday_name = "";
1889  break;
1890  }
1891  }
1892 
1893  return weekday_name;
1894 }
1895 
1896 /*
1897  * local_long_weekday_name() - Return the long weekday name for the given
1898  * weekday number (0-6)
1899  * return:
1900  * weekday(in) :
1901  */
1902 static const char *
1903 local_long_weekday_name (int weekday)
1904 {
1905  const char *weekday_name;
1906 
1907  assert (weekday >= 0 && weekday <= 6);
1908 
1909  switch (intl_zone (LC_TIME))
1910  {
1911  case INTL_ZONE_US:
1912  {
1913  weekday_name = eng_long_weekday_names[weekday];
1914  break;
1915  }
1916  case INTL_ZONE_KR:
1917  {
1918  weekday_name = kor_weekday_names[weekday];
1919  break;
1920  }
1921  default:
1922  {
1923  assert (!"Zone not implemented!");
1924  weekday_name = "";
1925  break;
1926  }
1927  }
1928 
1929  return weekday_name;
1930 }
1931 #endif
1932 
1933 /*
1934  * local_date_string() - Return a string representing the given date in the
1935  * locale's date format.
1936  * return:
1937  * month(in) :
1938  * day(in) :
1939  * year(in) :
1940  */
1941 static const char *
1942 local_date_string (int month, int day, int year)
1943 {
1944  const char *value;
1945 
1946  switch (intl_zone (LC_TIME))
1947  {
1948  case INTL_ZONE_US:
1949  {
1950  value = us_date_string (month, day, year);
1951  break;
1952  }
1953  case INTL_ZONE_KR:
1954  {
1955  value = ko_date_string (month, day, year);
1956  break;
1957  }
1958  default:
1959  {
1960  assert (!"Zone not implemented!");
1961  value = "";
1962  break;
1963  }
1964  }
1965 
1966  return value;
1967 }
1968 
1969 /*
1970  * local_date_value() - Scan tokens and parse a date value in the locale's
1971  * date format. If a valid value can't be found, then return an error
1972  * condition. otherwise, set the_month, the_day, and the_year to the
1973  * value found.
1974  * return:
1975  * the_month(out) :
1976  * the_day(out) :
1977  * the_year(out) :
1978  */
1979 static int
1980 local_date_value (int *the_month, int *the_day, int *the_year)
1981 {
1982  int value;
1983 
1984  switch (intl_zone (LC_TIME))
1985  {
1986  case INTL_ZONE_US:
1987  {
1988  value = us_date_value (the_month, the_day, the_year);
1989  break;
1990  }
1991  case INTL_ZONE_KR:
1992  {
1993  value = ko_date_value (the_month, the_day, the_year);
1994  break;
1995  }
1996  default:
1997  {
1998  assert (!"Zone not implemented!");
1999  value = 0;
2000  break;
2001  }
2002  }
2003 
2004  return value;
2005 }
2006 
2007 #if defined (ENABLE_UNUSED_FUNCTION)
2008 /*
2009  * local_alt_date_string() - Return a string representing the given date in the
2010  * locale's alternate date format.
2011  * return:
2012  * month(in) :
2013  * day(in) :
2014  * year(in) :
2015  */
2016 static const char *
2017 local_alt_date_string (int month, int day, int year)
2018 {
2019  const char *value;
2020 
2021  switch (intl_zone (LC_TIME))
2022  {
2023  case INTL_ZONE_US:
2024  {
2025  value = us_alt_date_string (month, day, year);
2026  break;
2027  }
2028  case INTL_ZONE_KR:
2029  {
2030  value = ko_alt_date_string (month, day, year);
2031  break;
2032  }
2033  default:
2034  {
2035  assert (!"Zone not implemented!");
2036  value = "";
2037  break;
2038  }
2039  }
2040 
2041  return value;
2042 }
2043 
2044 /*
2045  * local_alt_date_value() - Scan tokens and parse a date value in the locale's
2046  * alternate date format. If a valid value can't be found, then return an
2047  * error condition. otherwise, set the_month, the_day, and the_year to the
2048  * value found.
2049  * return:
2050  * the_month(in) :
2051  * the_day(in) :
2052  * the_year(in) :
2053  */
2054 static int
2055 local_alt_date_value (int *the_month, int *the_day, int *the_year)
2056 {
2057  int value;
2058 
2059  switch (intl_zone (LC_TIME))
2060  {
2061  case INTL_ZONE_US:
2062  {
2063  value = us_alt_date_value (the_month, the_day, the_year);
2064  break;
2065  }
2066  case INTL_ZONE_KR:
2067  {
2068  value = ko_alt_date_value (the_month, the_day, the_year);
2069  break;
2070  }
2071  default:
2072  {
2073  assert (!"Zone not implemented!");
2074  value = 0;
2075  break;
2076  }
2077  }
2078 
2079  return value;
2080 }
2081 #endif
2082 
2083 /*
2084  * local_time_string() - Return a string representing the given time in the
2085  * locale's time format.
2086  * return:
2087  * the_time(in) :
2088  */
2089 static const char *
2090 local_time_string (const DB_TIME * the_time)
2091 {
2092  const char *value;
2093 
2094  switch (intl_zone (LC_TIME))
2095  {
2096  case INTL_ZONE_US:
2097  {
2098  value = us_time_string (the_time);
2099  break;
2100  }
2101  case INTL_ZONE_KR:
2102  {
2103  value = ko_time_string (the_time);
2104  break;
2105  }
2106  default:
2107  {
2108  assert (!"Zone not implemented!");
2109  value = "";
2110  break;
2111  }
2112  }
2113 
2114  return value;
2115 }
2116 
2117 /*
2118  * local_time_value() - Scan tokens and parse a time value in the locale's
2119  * time format. If a valid value can't be found, then return an error
2120  * condition. otherwise, set the_hour, the_min, and the_sec to the value
2121  * found.
2122  * return:
2123  * the_hour(out) :
2124  * the_min(out) :
2125  * the_sec(out) :
2126  */
2127 static int
2128 local_time_value (int *the_hour, int *the_min, int *the_sec)
2129 {
2130  int value;
2131 
2132  switch (intl_zone (LC_TIME))
2133  {
2134  case INTL_ZONE_US:
2135  {
2136  value = us_time_value (the_hour, the_min, the_sec);
2137  break;
2138  }
2139  case INTL_ZONE_KR:
2140  {
2141  value = ko_time_value (the_hour, the_min, the_sec);
2142  break;
2143  }
2144  default:
2145  {
2146  assert (!"Zone not implemented!");
2147  value = 0;
2148  break;
2149  }
2150  }
2151 
2152  return value;
2153 }
2154 
2155 /*
2156  * local_am_pm_string() - Return a string representing AM/PM for
2157  * the given time.
2158  * return:
2159  * the_time(in) :
2160  */
2161 static const char *
2162 local_am_pm_string (const DB_TIME * the_time)
2163 {
2164  int hour, min, sec;
2165  db_time_decode ((DB_TIME *) the_time, &hour, &min, &sec);
2166  return hour >= 12 ? local_pm () : local_am ();
2167 }
2168 
2169 /*
2170  * local_am_pm_value() - Scan tokens and parse an AM/PM value in the locale's
2171  * time format. If a valid value can't be found, then return an error
2172  * condition. otherwise, set pm to true/false if PM/AM found.
2173  * return:
2174  * pm(out):
2175  */
2176 static int
2178 {
2179  int error = 0;
2180  FMT_TOKEN token;
2181 
2182  if (cnv_fmt_lex (&token) != FT_AM_PM)
2183  {
2184  error = CNV_ERR_BAD_AM_PM;
2185  co_signal (error, CNV_ER_FMT_BAD_AM_PM, "p");
2186  }
2187  else
2188  {
2189  *pm = (bool) token.value;
2190  }
2191 
2192  return error;
2193 }
2194 
2195 #if defined (ENABLE_UNUSED_FUNCTION)
2196 /*
2197  * local_timestamp_string() - Return a string representing the given timestamp
2198  * in the locale's timestamp format.
2199  * return:
2200  * the_timestamp(in) :
2201  */
2202 static const char *
2203 local_timestamp_string (const DB_TIMESTAMP * the_timestamp)
2204 {
2205  const char *value;
2206 
2207  switch (intl_zone (LC_TIME))
2208  {
2209  case INTL_ZONE_US:
2210  {
2211  value = us_timestamp_string (the_timestamp);
2212  break;
2213  }
2214  case INTL_ZONE_KR:
2215  {
2216  value = ko_timestamp_string (the_timestamp);
2217  break;
2218  }
2219  default:
2220  {
2221  assert (!"Zone not implemented!");
2222  value = "";
2223  break;
2224  }
2225  }
2226 
2227  return value;
2228 }
2229 
2230 /*
2231  * local_timestamp_value() - Scan tokens and parse timestamp value in the
2232  * locale's timestamp format. If a valid value can't be found, then
2233  * return an error condition. otherwise, set the_day, the_month, the_year,
2234  * the_hour (0-23), the_min, and the_sec to the value found.
2235  * return:
2236  * the_month(out) :
2237  * the_day(out) :
2238  * the_year(out) :
2239  * the_hour(out) :
2240  * the_min(out) :
2241  * the_sec(out) :
2242  */
2243 static int
2244 local_timestamp_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec)
2245 {
2246  int value;
2247 
2248  switch (intl_zone (LC_TIME))
2249  {
2250  case INTL_ZONE_US:
2251  {
2252  value = us_timestamp_value (the_month, the_day, the_year, the_hour, the_min, the_sec);
2253  break;
2254  }
2255  case INTL_ZONE_KR:
2256  {
2257  value = ko_timestamp_value (the_month, the_day, the_year, the_hour, the_min, the_sec);
2258  break;
2259  }
2260  default:
2261  {
2262  assert (!"Zone not implemented!");
2263  value = 0;
2264  break;
2265  }
2266  }
2267 
2268  return value;
2269 }
2270 
2271 /*
2272  * local_datetime_string() - Return a string representing the given timestamp
2273  * in the locale's timestamp format.
2274  * return:
2275  * the_timestamp(in) :
2276  */
2277 static const char *
2278 local_datetime_string (const DB_DATETIME * the_datetime)
2279 {
2280  const char *value;
2281 
2282  switch (intl_zone (LC_TIME))
2283  {
2284  case INTL_ZONE_US:
2285  {
2286  value = us_datetime_string (the_datetime);
2287  break;
2288  }
2289  case INTL_ZONE_KR:
2290  {
2291  value = ko_datetime_string (the_datetime);
2292  break;
2293  }
2294  default:
2295  {
2296  assert (!"Zone not implemented!");
2297  value = "";
2298  break;
2299  }
2300  }
2301 
2302  return value;
2303 }
2304 
2305 /*
2306  * local_datetime_value() -
2307  * return:
2308  * the_month(out) :
2309  * the_day(out) :
2310  * the_year(out) :
2311  * the_hour(out) :
2312  * the_min(out) :
2313  * the_sec(out) :
2314  */
2315 static int
2316 local_datetime_value (int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec,
2317  int *the_msec)
2318 {
2319  int value;
2320 
2321  switch (intl_zone (LC_TIME))
2322  {
2323  case INTL_ZONE_US:
2324  {
2325  value = us_datetime_value (the_month, the_day, the_year, the_hour, the_min, the_sec, the_msec);
2326  break;
2327  }
2328  case INTL_ZONE_KR:
2329  {
2330  value = ko_datetime_value (the_month, the_day, the_year, the_hour, the_min, the_sec, the_msec);
2331  break;
2332  }
2333  default:
2334  {
2335  assert (!"Zone not implemented!");
2336  value = 0;
2337  break;
2338  }
2339  }
2340 
2341  return value;
2342 }
2343 #endif /* ENABLE_UNUSED_FUNCTION */
2344 
2345 /*
2346  * Basic Utility Functions
2347  */
2348 
2349 /*
2350  * cnv_wcs() - Return the result of converting the given multibyte string
2351  * to wide characters.
2352  * return:
2353  * mbs(in) :
2354  */
2355 static const wchar_t *
2356 cnv_wcs (const char *mbs)
2357 {
2358 #if defined(SERVER_MODE)
2359  ADJ_ARRAY *buffer = cnv_get_thread_local_adj_buffer (0);
2360 #else
2361  ADJ_ARRAY *buffer = cnv_adj_buffer1;
2362 #endif
2363  size_t nchars;
2364  wchar_t *wchars;
2365 
2366  assert (mbs);
2367 
2368  /* Initialize buffer. */
2369  if (!buffer)
2370  {
2371 #if defined(SERVER_MODE)
2372  buffer = adj_ar_new (sizeof (wchar_t), 0, 1.0);
2373  cnv_set_thread_local_adj_buffer (0, buffer);
2374 #else
2375  buffer = cnv_adj_buffer1 = adj_ar_new (sizeof (wchar_t), 0, 1.0);
2376 #endif
2377  }
2378  adj_ar_replace (buffer, NULL, strlen (mbs) + 1, 0, ADJ_AR_EOA);
2379 
2380  wchars = (wchar_t *) adj_ar_get_buffer (buffer);
2381  nchars = mbstowcs (wchars, mbs, adj_ar_length (buffer));
2382  assert ((int) nchars < adj_ar_length (buffer));
2383 
2384  return (const wchar_t *) wchars;
2385 }
2386 
2387 /*
2388  * cnv_currency_zone() - Return the locale zone associated with the given
2389  * currency type.
2390  * return:
2391  * currency(in) :
2392  */
2393 static INTL_ZONE
2395 {
2396  /* quiet compiler with assignment */
2397  INTL_ZONE zone = INTL_ZONE_US;
2398 
2399  assert (cnv_valid_currency (currency));
2400 
2401  switch (currency)
2402  {
2403  case DB_CURRENCY_DOLLAR:
2404  {
2405  zone = INTL_ZONE_US;
2406  break;
2407  }
2408  case DB_CURRENCY_YEN:
2409  {
2410  break;
2411  }
2412  case DB_CURRENCY_WON:
2413  {
2414  zone = INTL_ZONE_KR;
2415  break;
2416  }
2417  case DB_CURRENCY_TL:
2418  {
2419  zone = INTL_ZONE_TR;
2420  break;
2421  }
2431  case DB_CURRENCY_EURO:
2442  {
2443  }
2444  break;
2445  default:
2446  break;
2447  }
2448 
2449  return zone;
2450 }
2451 
2452 #if defined (ENABLE_UNUSED_FUNCTION)
2453 /*
2454  * cnv_currency_symbol() - Return the currency symbol string for the given
2455  * currency type.
2456  * return:
2457  * currency(in) :
2458  */
2459 static const char *
2460 cnv_currency_symbol (DB_CURRENCY currency)
2461 {
2462  const char *symbol;
2463 
2464  assert (cnv_valid_currency (currency));
2465 
2466  switch (currency)
2467  {
2468  case DB_CURRENCY_DOLLAR:
2469  {
2470  symbol = "$";
2471  break;
2472  }
2473  case DB_CURRENCY_WON:
2474  {
2475  symbol = "\\";
2476  break;
2477  }
2478 
2479  case DB_CURRENCY_YEN:
2480  case DB_CURRENCY_POUND:
2481  default:
2482  {
2483  assert (!"Currency symbol not implemented!");
2484  symbol = "";
2485  break;
2486  }
2487  }
2488 
2489  return symbol;
2490 }
2491 #endif
2492 
2493 /*
2494  * cnv_valid_currency() - Return true if currency type is valid.
2495  * return:
2496  * currency(in) :
2497  */
2498 static bool
2500 {
2501  bool valid = true;
2502 
2503  switch (currency)
2504  {
2505  case DB_CURRENCY_DOLLAR:
2506  case DB_CURRENCY_YEN:
2507  case DB_CURRENCY_WON:
2508  case DB_CURRENCY_TL:
2518  case DB_CURRENCY_EURO:
2529  {
2530  break;
2531  }
2532 
2533  default:
2534  {
2535  valid = false;
2536  break;
2537  }
2538  }
2539 
2540  return valid;
2541 }
2542 
2543 #if defined (ENABLE_UNUSED_FUNCTION)
2544 /*
2545  * cnv_valid_timestamp() - Return true if the give time lies in the range
2546  * which can be encoded as a valid timestamp. If false, then signal an
2547  * error condition.
2548  * return:
2549  * the_date(in) :
2550  * the_time(in) :
2551  */
2552 static bool
2553 cnv_valid_timestamp (DB_DATE * the_date, DB_TIME * the_time)
2554 {
2555  static DB_TIMESTAMP min_timestamp = 0;
2556  static DB_TIMESTAMP max_timestamp = INT_MAX;
2557  static DB_DATE min_date;
2558  static DB_DATE max_date = 0;
2559  static DB_TIME min_time;
2560  static DB_TIME max_time;
2561  bool valid = false;
2562 
2563  if (!max_date)
2564  {
2565  /* Initialize timestamp range constants. */
2566  db_timestamp_decode_ses (&min_timestamp, &min_date, &min_time);
2567  db_timestamp_decode_ses (&max_timestamp, &max_date, &max_time);
2568  }
2569 
2570  if (*the_date < min_date || (*the_date == min_date && *the_time < min_time))
2571  {
2572  char limit[FMT_MAX_TIMESTAMP_STRING + 1];
2573  db_timestamp_string (&min_timestamp, "", limit, sizeof limit);
2575  }
2576  else if (*the_date > max_date || (*the_date == max_date && *the_time > max_time))
2577  {
2578  char limit[FMT_MAX_TIMESTAMP_STRING + 1];
2579  db_timestamp_string (&max_timestamp, "", limit, sizeof limit);
2581  }
2582  else
2583  {
2584  valid = true;
2585  }
2586 
2587  return valid;
2588 }
2589 
2590 /*
2591  * cnv_get_string_buffer() - Return an empty array big enough to store
2592  * a NUL-terminated string of the given length.
2593  * return:
2594  * nchars(in) :
2595  */
2596 static ADJ_ARRAY *
2597 cnv_get_string_buffer (int nchars)
2598 {
2599 #if defined(SERVER_MODE)
2600  ADJ_ARRAY *buffer = cnv_get_thread_local_adj_buffer (1);
2601 #else
2602  ADJ_ARRAY *buffer = cnv_adj_buffer2;
2603 #endif
2604 
2605  assert (nchars >= 0);
2606 
2607  nchars++;
2608 
2609  if (!buffer)
2610  {
2611 #if defined(SERVER_MODE)
2612  buffer = adj_ar_new (sizeof (char), nchars, 1.0);
2613  cnv_set_thread_local_adj_buffer (1, buffer);
2614 #else
2615  buffer = cnv_adj_buffer2 = adj_ar_new (sizeof (char), nchars, 1.0);
2616 #endif
2617  }
2618  adj_ar_replace (buffer, NULL, nchars, 0, ADJ_AR_EOA);
2619 
2620  return buffer;
2621 }
2622 #endif /* ENABLE_UNUSED_FUNCTION */
2623 
2624 /*
2625  * cnv_get_value_string_buffer() - Return an empty array used to accumulate a
2626  * value string. Ensure array is big enough to hold the given number of
2627  * chars.
2628  * return:
2629  * nchars(in):
2630  */
2631 static ADJ_ARRAY *
2633 {
2634 #if defined(SERVER_MODE)
2635  ADJ_ARRAY *buffer = cnv_get_thread_local_adj_buffer (2);
2636 #else
2637  ADJ_ARRAY *buffer = cnv_adj_buffer3;
2638 #endif
2639 
2640  assert (nchars >= 0);
2641 
2642  if (nchars)
2643  {
2644  nchars++;
2645  }
2646 
2647  if (!buffer)
2648  {
2649 #if defined(SERVER_MODE)
2650  buffer = adj_ar_new (sizeof (char), nchars, 1.0);
2651  cnv_set_thread_local_adj_buffer (2, buffer);
2652 #else
2653  buffer = cnv_adj_buffer3 = adj_ar_new (sizeof (char), nchars, 1.0);
2654 #endif
2655  }
2656  adj_ar_replace (buffer, NULL, nchars, 0, ADJ_AR_EOA);
2657 
2658  return buffer;
2659 }
2660 
2661 /*
2662  * cnv_bad_char() - Signal an error for an invalid character.
2663  * If unknown is true, then the bad char is unrecognizable.
2664  * otherwise, the bad char is a valid char that is out of place.
2665  * return:
2666  * string(in) :
2667  * unknown(in) :
2668  */
2669 static int
2670 cnv_bad_char (const char *string, bool unknown)
2671 {
2672  int error = unknown ? CNV_ERR_BAD_CHAR : CNV_ERR_BAD_POSITION;
2673 
2674  char the_char[MB_LEN_MAX + 1];
2675  int nbytes;
2676 
2677  /* Find length of first char. */
2678  while ((nbytes = mblen (string, strlen (string))) < 0)
2679  {
2680  string = "?";
2681  }
2682 
2683  /* Create 1-char string. */
2684  strncpy (the_char, string, nbytes);
2685  strcpy (the_char + nbytes, "");
2686  assert (strlen (the_char) < (int) sizeof (the_char));
2687 
2688  co_signal (error, unknown ? CNV_ER_FMT_BAD_CHAR : CNV_ER_FMT_BAD_POSITION, the_char);
2689  return error;
2690 }
2691 
2692 #if defined (ENABLE_UNUSED_FUNCTION)
2693 /*
2694  * fmt_validate() - Return an error if the given format is invalid.
2695  * return:
2696  * format(in) :
2697  * mode(in) :
2698  * fmt_type(in) :
2699  * data_type(in) :
2700  */
2701 static int
2702 fmt_validate (const char *format, FMT_LEX_MODE mode, FMT_TOKEN_TYPE fmt_type, DB_TYPE data_type)
2703 {
2704  FMT_TOKEN token;
2705  FMT_TOKEN_TYPE ttype;
2706  int error = 0;
2707 
2708  cnv_fmt_analyze (format, mode);
2709  ttype = cnv_fmt_lex (&token);
2710  if (!(ttype == FT_NONE || (ttype == fmt_type && cnv_fmt_lex (&token) == FT_NONE)))
2711  {
2712  error = CNV_ERR_BAD_FORMAT;
2714  }
2715  return error;
2716 }
2717 #endif
2718 
2719 /*
2720  * fmt_integral_value() - Scan tokens and parse an integral value. If a valid
2721  * value can't be found, then return an error condition. otherwise, set
2722  * the_value to the value found.
2723  * return:
2724  * digit_type(in): the type of digit chars allowed
2725  * ndigits(in): the maximum number of digits
2726  * sign_required(in): If true ,then a positive/negative sign token must
2727  * be present.
2728  * thousands(in): If true , then thousands separators must be included.
2729  * the_value(out):
2730  */
2731 static int
2732 fmt_integral_value (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands, double *the_value)
2733 {
2734  int nfound;
2735  int error;
2736 
2737  error = fmt_integral_digits (digit_type, ndigits, sign_required, thousands, the_value, &nfound);
2738 
2739  if (!error && ndigits)
2740  {
2741  /* Too many digits? */
2742  if (nfound > ndigits)
2743  {
2744  error = CNV_ERR_EXTRA_INTEGER;
2746  }
2747  /* Enough digits found? */
2748  else if (digit_type != DIGIT_Z && nfound < ndigits)
2749  {
2750  error = CNV_ERR_MISSING_INTEGER;
2752  }
2753  }
2754 
2755  return error;
2756 }
2757 
2758 /*
2759  * fmt_integral_digits() - Scan tokens and parse an integral value. If a valid
2760  * value can't be found, then return an error condition. otherwise, set
2761  * the_value to the value found.
2762  * return:
2763  * digit_type(in) : the type of digit chars allowed
2764  * ndigits(in) : the maximum number of digits
2765  * sign_required(in) : If true, then a positive/negative sign token must be
2766  * present.
2767  * thousands(in) : If true, then thousands separators must be included.
2768  * the_value(out) :
2769  * nfound(out) : the number of digits in the value.
2770  */
2771 static int
2772 fmt_integral_digits (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands, double *the_value,
2773  int *nfound)
2774 {
2775  int error = 0;
2776 
2777  *the_value = 0.0;
2778 
2779  do
2780  {
2781  FMT_TOKEN_TYPE leading = FT_NONE;
2782  int nleading = 0;
2783  FMT_TOKEN token;
2784  FMT_TOKEN_TYPE type = cnv_fmt_lex (&token);
2785  bool negative = (type == FT_MINUS);
2786 
2787  /* Sign? */
2788  if (negative || (sign_required && type == FT_PLUS))
2789  {
2790  /* Yes, scan next token. */
2791  type = cnv_fmt_lex (&token);
2792  if (type == FT_PLUS || type == FT_MINUS)
2793  {
2794  error = CNV_ERR_EXTRA_SIGN;
2796  break;
2797  }
2798  }
2799  else if (sign_required)
2800  {
2801  cnv_fmt_unlex ();
2802  error = CNV_ERR_NO_SIGN;
2804  break;
2805  }
2806 
2807  /* Leading fill chars? */
2808  *nfound = 0;
2809  if (type == FT_ZEROES || type == FT_STARS)
2810  {
2811  /* Yes, scan next token. */
2812  leading = type;
2813  nleading = intl_mbs_len (token.text);
2814  type = cnv_fmt_lex (&token);
2815  }
2816 
2817  /* Any numeric chars left? */
2818  if (type == FT_NUMBER)
2819  {
2820  int initial_digits = 0;
2821  int group_size = *local_grouping ();
2822 
2823  /* Yes, add to numeric value. */
2824  for (; type == FT_NUMBER || type == FT_ZEROES; type = cnv_fmt_lex (&token))
2825  {
2826  int tdigits = intl_mbs_len (token.text);
2827  if (thousands && group_size != CHAR_MAX && ((initial_digits += tdigits) > group_size))
2828  {
2829  error = CNV_ERR_BAD_THOUS;
2831  break;
2832  }
2833 
2834  *the_value = *the_value * pow (10.0, tdigits) + strtod (token.text, NULL);
2835 
2836  *nfound += tdigits;
2837  }
2838 
2839  /* Add thousands groups, if necessary. */
2840  if (thousands)
2841  {
2842  for (; type == FT_THOUSANDS; type = cnv_fmt_lex (&token))
2843  {
2844  int tdigits = intl_mbs_len (token.text);
2845  *the_value = *the_value * pow (10.0, tdigits) + strtod (token.text, NULL);
2846  *nfound += tdigits;
2847  }
2848  if (type == FT_NUMBER || type == FT_ZEROES
2849  || (type == FT_UNKNOWN && mbs_eql (token.text, local_thousands ())))
2850  {
2851  error = CNV_ERR_BAD_THOUS;
2853  break;
2854  }
2855  }
2856 
2857  /* Apply sign. */
2858  if (negative)
2859  {
2860  *the_value = -(*the_value);
2861  }
2862  }
2863 
2864  /* Assert: we've scanned following token, so put it back. */
2865  cnv_fmt_unlex ();
2866 
2867  /* Valid leading fill chars? */
2868  if (leading != FT_NONE)
2869  {
2870  if ((leading == FT_STARS && digit_type != DIGIT_STAR) || (leading == FT_ZEROES && !(digit_type == DIGIT_9 ||
2871  /* allow singleton zero. */
2872  (digit_type == DIGIT_Z
2873  && nleading == 1
2874  && *the_value == 0.0))))
2875  {
2876 
2877  error = CNV_ERR_BAD_LEADING;
2879  break;
2880  }
2881 
2882  *nfound += nleading;
2883  }
2884  }
2885  while (0);
2886 
2887  return error;
2888 }
2889 
2890 /*
2891  * fmt_fractional_digits() - Scan tokens and parse fractional value. If a
2892  * valid value can't be found, then return an error condition. otherwise,
2893  * set the_value to the value found.
2894  * return:
2895  * digit_type(in) :the type of digit chars allowed
2896  * ndigits(in) : the maximum number of digits
2897  * the_value(out) :
2898  * nfound(out) : set to the number of digits in the value.
2899  */
2900 static int
2901 fmt_fractional_digits (FORMAT_DIGIT digit_type, int ndigits, double *the_value, int *nfound)
2902 {
2903  int error = 0;
2904 
2905  *the_value = 0.0;
2906  *nfound = 0;
2907 
2908  do
2909  {
2910  FMT_TOKEN token;
2911  FMT_TOKEN_TYPE type;
2912  FMT_TOKEN_TYPE last = FT_NONE;
2913  double exponent = 0.0;
2914 
2915  /* Any numeric chars? */
2916  for (; (type = cnv_fmt_lex (&token)) == FT_NUMBER || type == FT_ZEROES; last = type)
2917  {
2918 
2919  /* Yes, add to numeric value. */
2920  int tdigits = intl_mbs_len (token.text);
2921  exponent -= tdigits;
2922  *the_value = *the_value + strtod (token.text, NULL) * pow (10.0, exponent);
2923 
2924  *nfound += tdigits;
2925  }
2926 
2927  /* Any trailing fill chars? */
2928  if (type == FT_STARS)
2929  {
2930  if (last != FT_ZEROES)
2931  {
2932  /* Can't have trailing zeroes AND trailing stars! */
2933  last = type;
2934  }
2935  *nfound += intl_mbs_len (token.text);
2936  }
2937  else
2938  {
2939  /* No, retry this token later. */
2940  cnv_fmt_unlex ();
2941  }
2942 
2943  /* Valid trailing fill chars? */
2944  if ((last == FT_ZEROES && (digit_type != DIGIT_9 && digit_type != DIGIT_Z))
2945  || (last == FT_STARS && digit_type != DIGIT_STAR))
2946  {
2947  error = CNV_ERR_BAD_TRAILING;
2949  break;
2950  }
2951  }
2952  while (0);
2953 
2954  return error;
2955 }
2956 
2957 /*
2958  * fmt_fractional_value() - Scan tokens and parse fractional value. If a valid
2959  * value can't be found, then return an error condition. otherwise, set
2960  * the_value to the value found.
2961  * return:
2962  * digit_type(in) : the type of digit chars allowed
2963  * ndigits(in) : the maximum number of digits
2964  * the_value(out) :
2965  */
2966 static int
2967 fmt_fractional_value (FORMAT_DIGIT digit_type, int ndigits, double *the_value)
2968 {
2969  int nfound;
2970 
2971  int error = fmt_fractional_digits (digit_type,
2972  ndigits,
2973  the_value,
2974  &nfound);
2975 
2976  if (ndigits)
2977  {
2978  /* Too many digits? */
2979  if (nfound > ndigits)
2980  {
2981  error = CNV_ERR_EXTRA_FRACTION;
2983  }
2984 
2985  /* Enough digits found? */
2986  else if (digit_type != DIGIT_Z && nfound < ndigits)
2987  {
2988  error = CNV_ERR_MISSING_FRACTION;
2990  }
2991  }
2992 
2993  return error;
2994 }
2995 
2996 #if defined (ENABLE_UNUSED_FUNCTION)
2997 /*
2998  * fmt_add_thousands() -
2999  * return:
3000  * string() :
3001  * position() :
3002  */
3003 static void
3004 fmt_add_thousands (ADJ_ARRAY * string, int *position)
3005 {
3006  FMT_TOKEN_TYPE ttype;
3007  FMT_TOKEN token;
3008  int start;
3009  int end;
3010  int sep_pos;
3011  int nbytes;
3012  int maxbytes;
3013  int ndigits;
3014  const char *next_char;
3015  const char *vstring = (const char *) adj_ar_get_buffer (string);
3016  const char *thous = local_thousands ();
3017  const char *group_size = local_grouping ();
3018 
3019  /* Find position of first digit */
3020  cnv_fmt_analyze (vstring, FL_LOCAL_NUMBER);
3021  while ((ttype = cnv_fmt_lex (&token)) == FT_MINUS || ttype == FT_PLUS || ttype == FT_CURRENCY || ttype == FT_ZEROES
3022  || ttype == FT_STARS);
3023  start = CAST_BUFLEN ((cnv_fmt_next_token () - token.length) - vstring);
3024 
3025  /* Find end of digits. */
3026  for (; ttype == FT_NUMBER || ttype == FT_ZEROES; ttype = cnv_fmt_lex (&token));
3027  end = CAST_BUFLEN ((cnv_fmt_next_token () - token.length) - vstring);
3028 
3029  /* Get number of digits. */
3030  for (ndigits = 0, next_char = vstring + start, maxbytes = end - start;
3031  maxbytes > 0 && (nbytes = mblen (next_char, maxbytes)); ndigits++, next_char += nbytes, maxbytes -= nbytes);
3032 
3033  /* Insert separators from right to left, according to grouping. */
3034  for (sep_pos = ndigits - *group_size; *group_size != CHAR_MAX && sep_pos > 0; sep_pos -= *group_size)
3035  {
3036 
3037  int insert;
3038 
3039  vstring = (const char *) adj_ar_get_buffer (string);
3040  insert = CAST_STRLEN (intl_mbs_nth (vstring + start, sep_pos) - vstring);
3041 
3042  adj_ar_insert (string, thous, strlen (thous), insert);
3043  if (position && *position > insert)
3044  {
3045  *position += strlen (thous);
3046  }
3047 
3048  if (*(group_size + 1))
3049  {
3050  group_size++;
3051  }
3052  }
3053 }
3054 
3055 /*
3056  * fmt_drop_thousands() -
3057  * return:
3058  * string() :
3059  * position() :
3060  */
3061 static void
3062 fmt_drop_thousands (ADJ_ARRAY * string, int *position)
3063 {
3064  const char *thous = local_thousands ();
3065  int tl = strlen (thous);
3066  const char *vstring = (const char *) adj_ar_get_buffer (string);
3067  int maxbytes;
3068  int nbytes;
3069 
3070  /* Scan value string chars. */
3071  for (maxbytes = strlen (vstring); maxbytes > 0 && (nbytes = mblen (vstring, maxbytes)); maxbytes -= nbytes)
3072  {
3073  /* Next char is thousands separator? */
3074  if (!strncmp (vstring, thous, tl))
3075  {
3076  /* Yes, remove from value string. */
3077  int i = vstring - (const char *) adj_ar_get_buffer (string);
3078  adj_ar_remove (string, i, i + tl);
3079  if (position && *position > i)
3080  {
3081  *position -= tl;
3082  }
3083  }
3084  else
3085  {
3086  /* No, skip to next char. */
3087  vstring += nbytes;
3088  }
3089  }
3090 }
3091 
3092 /*
3093  * fmt_add_integral() -
3094  * return:
3095  * string() :
3096  * position() :
3097  * ndigits() :
3098  * type() :
3099  * mode() :
3100  */
3101 static void
3102 fmt_add_integral (ADJ_ARRAY * string, int *position, int ndigits, FORMAT_DIGIT type, FMT_LEX_MODE mode)
3103 {
3104  int i;
3105  FMT_TOKEN token;
3106  FMT_TOKEN_TYPE ttype;
3107  const char *digit = type == DIGIT_9 ? LOCAL_0 : LOCAL_STAR;
3108  const char *vstring = (const char *) adj_ar_get_buffer (string);
3109 
3110  assert (type != DIGIT_Z);
3111 
3112  /* Find position of first integral digit. */
3113  cnv_fmt_analyze (vstring, mode);
3114  while ((ttype = cnv_fmt_lex (&token)) == FT_MINUS || ttype == FT_PLUS || ttype == FT_CURRENCY);
3115  i = (cnv_fmt_next_token () - strlen (token.raw_text)) - vstring;
3116 
3117  if (position && *position > i)
3118  {
3119  *position += strlen (digit) * ndigits;
3120  }
3121  while (ndigits-- > 0)
3122  {
3123  adj_ar_insert (string, digit, strlen (digit), i);
3124  }
3125 }
3126 
3127 /*
3128  * fmt_drop_integral() -
3129  * return:
3130  * string() :
3131  * position() :
3132  * ndigits() :
3133  * mode() :
3134  */
3135 static void
3136 fmt_drop_integral (ADJ_ARRAY * string, int *position, int ndigits, FMT_LEX_MODE mode)
3137 {
3138  const char *vstring = (const char *) adj_ar_get_buffer (string);
3139  FMT_TOKEN token;
3140  FMT_TOKEN_TYPE ttype;
3141  int i;
3142  int nd;
3143  int ndbytes;
3144  int maxbytes;
3145  int nbytes;
3146  const char *sp;
3147 
3148  /* Find position of first integral digit. */
3149  cnv_fmt_analyze (vstring, mode);
3150  while ((ttype = cnv_fmt_lex (&token)) == FT_MINUS || ttype == FT_PLUS || ttype == FT_CURRENCY);
3151  i = (cnv_fmt_next_token () - strlen (token.raw_text)) - vstring;
3152  vstring += i;
3153 
3154  /* Determine number of bytes to drop. */
3155  for (nd = 0, sp = vstring, maxbytes = strlen (sp); nd < ndigits && (nbytes = mblen (sp, maxbytes));
3156  nd++, sp += nbytes, maxbytes -= nbytes);
3157  ndbytes = sp - vstring;
3158 
3159  /* Drop digit bytes. */
3160  adj_ar_remove (string, i, i + ndbytes);
3161 
3162  /* Adjust position. */
3163  if (position && *position > i)
3164  {
3165  if (ndbytes > *position - i)
3166  {
3167  ndbytes = *position - i;
3168  }
3169  *position -= ndbytes;
3170  }
3171 }
3172 
3173 /*
3174  * fmt_add_decimal() -
3175  * return:
3176  * string() :
3177  * position() :
3178  */
3179 static bool
3180 fmt_add_decimal (ADJ_ARRAY * string, int *position)
3181 {
3182  bool ok;
3183  FMT_TOKEN_TYPE ttype;
3184  FMT_TOKEN token;
3185  const char *vstring = (const char *) adj_ar_get_buffer (string);
3186 
3187  cnv_fmt_analyze (vstring, FL_LOCAL_NUMBER);
3188  while ((ttype = cnv_fmt_lex (&token)) == FT_MINUS || ttype == FT_PLUS || ttype == FT_CURRENCY);
3189 
3190  /*
3191  * Add decimal only if at most one digit already exists. This allows us to
3192  * automatically add a decimal when interactive input begins, but then reject
3193  * attempt to drop decimal later (when we wouldn't know where to put it
3194  * back).
3195  */
3196  ok = ttype == FT_NONE || ((ttype == FT_ZEROES || ttype == FT_NUMBER) && intl_mbs_len (token.text) == 1);
3197 
3198  if (ok)
3199  {
3200  const char *dp = local_decimal ();
3201  int insert = cnv_fmt_next_token () - vstring;
3202  adj_ar_insert (string, dp, strlen (dp), insert);
3203 
3204  if (position && *position > insert)
3205  {
3206  *position += strlen (dp);
3207  }
3208  }
3209 
3210  return ok;
3211 }
3212 
3213 /*
3214  * fmt_fraction_position() - Return the position immediately following the
3215  * first decimal in the given string after the given start position.
3216  * Return ADJ_AR_EOA if string doesn't contain a decimal after the start
3217  * position.
3218  * return:
3219  * string(in) :
3220  * start(in) :
3221  */
3222 static int
3223 fmt_fraction_position (ADJ_ARRAY * string, int start)
3224 {
3225  int return_pos = (int) ADJ_AR_EOA;
3226  const char *vstring = (const char *) adj_ar_get_buffer (string);
3227 
3228  if (start >= 0 && start < (int) strlen (vstring))
3229  {
3230  FMT_TOKEN_TYPE ttype;
3231  FMT_TOKEN token;
3232  int pos;
3233 
3234  cnv_fmt_analyze (vstring + start, FL_LOCAL_NUMBER);
3235 
3236  for (pos = 0, ttype = FT_NONE; (ttype = cnv_fmt_lex (&token)) && ttype != FT_DECIMAL;
3237  pos += strlen (token.raw_text));
3238 
3239  if (ttype == FT_DECIMAL)
3240  {
3241  return_pos = start + pos + strlen (token.raw_text);
3242  }
3243  }
3244 
3245  return return_pos;
3246 }
3247 
3248 /*
3249  * fmt_decimals() - Return the number of decimals in the given string.
3250  * return :
3251  * string(in) :
3252  */
3253 static int
3254 fmt_decimals (ADJ_ARRAY * string)
3255 {
3256  int n;
3257  int p;
3258 
3259  for (n = 0, p = 0; (p = fmt_fraction_position (string, p)) != ADJ_AR_EOA; n++);
3260 
3261  return n;
3262 }
3263 
3264 /*
3265  * fmt_add_fractional() -
3266  * return:
3267  * string() :
3268  * position() :
3269  * ndigits() :
3270  * type() :
3271  */
3272 static void
3273 fmt_add_fractional (ADJ_ARRAY * string, int *position, int ndigits, FORMAT_DIGIT type)
3274 {
3275  int insert;
3276  FMT_TOKEN_TYPE ttype;
3277  FMT_TOKEN token;
3278  const char *vstring = (const char *) adj_ar_get_buffer (string);
3279  const char *digit = type == DIGIT_9 ? LOCAL_0 : LOCAL_STAR;
3280 
3281  assert (type != DIGIT_Z);
3282 
3283  cnv_fmt_analyze (vstring, FL_LOCAL_NUMBER);
3284  while (cnv_fmt_lex (&token) != FT_DECIMAL);
3285  while ((ttype = cnv_fmt_lex (&token)) == FT_ZEROES || ttype == FT_NUMBER || ttype == FT_STARS);
3286  insert = (cnv_fmt_next_token () - strlen (token.raw_text)) - vstring;
3287 
3288  if (position && *position > insert)
3289  {
3290  *position += strlen (digit) * ndigits;
3291  }
3292  while (ndigits-- > 0)
3293  {
3294  adj_ar_insert (string, digit, strlen (digit), insert);
3295  }
3296 }
3297 
3298 /*
3299  * fmt_drop_fractional() -
3300  * return:
3301  * string() :
3302  * position() :
3303  * max_digits() :
3304  */
3305 static void
3306 fmt_drop_fractional (ADJ_ARRAY * string, int *position, int max_digits)
3307 {
3308  int first;
3309  int nd;
3310  int ndbytes;
3311  int nbytes;
3312  const char *sp;
3313  FMT_TOKEN_TYPE ttype;
3314  FMT_TOKEN token;
3315  const char *vstring = (const char *) adj_ar_get_buffer (string);
3316 
3317  /* Find first fractional digit. */
3318  cnv_fmt_analyze (vstring, FL_LOCAL_NUMBER);
3319  while (cnv_fmt_lex (&token) != FT_DECIMAL);
3320  first = cnv_fmt_next_token () - vstring;
3321  vstring += first;
3322 
3323  /* Find total bytes of fractional digits. */
3324  while ((ttype = cnv_fmt_lex (&token)) == FT_ZEROES || ttype == FT_NUMBER || ttype == FT_STARS);
3325  ndbytes = (cnv_fmt_next_token () - strlen (token.raw_text)) - vstring;
3326 
3327  /* Determine number of bytes to drop. */
3328  for (nd = 0, sp = vstring; nd < max_digits && (nbytes = mblen (sp, ndbytes)); nd++, sp += nbytes, ndbytes -= nbytes);
3329  first += sp - vstring;
3330 
3331  /* Drop digit bytes. */
3332  adj_ar_remove (string, first, first + ndbytes);
3333 
3334  if (position && *position > first)
3335  {
3336  /* Adjust position. */
3337  if (ndbytes > *position - first)
3338  {
3339  ndbytes = *position - first;
3340  }
3341  *position -= ndbytes;
3342  }
3343 }
3344 
3345 /*
3346  * fmt_add_currency() -
3347  * return:
3348  * string() :
3349  * position() :
3350  * mfmt() :
3351  */
3352 static void
3353 fmt_add_currency (ADJ_ARRAY * string, int *position, MONETARY_FORMAT * mfmt)
3354 {
3355  int i;
3356  const char *csymbol;
3357 
3358  if (mfmt->format == CURRENCY_FIRST)
3359  {
3360  i = 0;
3361  }
3362  else if (mfmt->format == CURRENCY_LAST)
3363  {
3364  i = strlen ((char *) adj_ar_get_buffer (string));
3365  }
3366  else
3367  {
3368  return;
3369  }
3370 
3371  csymbol = cnv_currency_symbol (mfmt->currency);
3372  adj_ar_insert (string, csymbol, strlen (csymbol), i);
3373  if (position && *position >= i)
3374  {
3375  *position += strlen (csymbol);
3376  }
3377 }
3378 #endif /* ENABLE_UNUSED_FUNCTION */
3379 
3380 /* cnvutil_cleanup() -This function cleans up any memory we may have allocated
3381  * along the way. These will be the three adj_arrays that can be allocated
3382  * by cnv_wcs, cnv_get_string_buffer and cnv_get_value_string_buffer.
3383  * return : void
3384  */
3385 static void
3387 {
3388 #if defined(SERVER_MODE)
3389  ADJ_ARRAY *buffer;
3390  int i;
3391 
3392  for (i = 0; i < 3; i++)
3393  {
3394  buffer = cnv_get_thread_local_adj_buffer (i);
3395  if (buffer)
3396  {
3397  adj_ar_free (buffer);
3398  }
3399  cnv_set_thread_local_adj_buffer (i, NULL);
3400  }
3401 
3402 #else
3403 
3404  if (cnv_adj_buffer1 != NULL)
3405  {
3406  adj_ar_free (cnv_adj_buffer1);
3407  cnv_adj_buffer1 = NULL;
3408  }
3409 
3410  if (cnv_adj_buffer2 != NULL)
3411  {
3412  adj_ar_free (cnv_adj_buffer2);
3413  cnv_adj_buffer2 = NULL;
3414  }
3415 
3416  if (cnv_adj_buffer3 != NULL)
3417  {
3418  adj_ar_free (cnv_adj_buffer3);
3419  cnv_adj_buffer3 = NULL;
3420  }
3421 #endif
3422 }
3423 
3424 
3425 /*
3426  * fmt_date_string() - Return a string representing the given date,
3427  * according to the given format descriptor.
3428  * return:
3429  * the_date(in) :
3430  * descriptor(in) :
3431  */
3432 static const char *
3433 fmt_date_string (const DB_DATE * the_date, const char *descriptor)
3434 {
3435  const char *string = NULL;
3436  int month, day, year;
3437 
3438  assert (mbs_eql (descriptor, "D") || mbs_eql (descriptor, "x") || mbs_eql (descriptor, "E"));
3439 
3440  db_date_decode ((DB_DATE *) the_date, &month, &day, &year);
3441 
3442 #if defined (ENABLE_UNUSED_FUNCTION)
3443  if (mbs_eql (descriptor, "D"))
3444  {
3445  static char date_string[FMT_MAX_DATE_STRING * MB_LEN_MAX + 1];
3446 
3447  sprintf (date_string, "%s%s%s%s%s", fmt_month_string (month, "m"), LOCAL_SLASH, fmt_monthday_string (day, "d"),
3448  LOCAL_SLASH, fmt_year_string (year, "y"));
3449  assert (strlen (date_string) < sizeof date_string);
3450 
3451  string = date_string;
3452  }
3453  else if (mbs_eql (descriptor, "E"))
3454  {
3455  string = local_alt_date_string (month, day, year);
3456  }
3457  else
3458 #endif
3459  if (mbs_eql (descriptor, "x"))
3460  {
3461  string = local_date_string (month, day, year);
3462  }
3463 
3464  return string;
3465 }
3466 
3467 #if defined (ENABLE_UNUSED_FUNCTION)
3468 /*
3469  * fmt_year_string() - Return a string representing the year of the given date,
3470  * according to the given format descriptor.
3471  * return:
3472  * the_date(in) :
3473  * descriptor(in) :
3474  */
3475 static const char *
3476 fmt_year_string (int year, const char *descriptor)
3477 {
3478  static char year_string[8 * MB_LEN_MAX + 1];
3479 
3480  assert (mbs_eql (descriptor, "y") || mbs_eql (descriptor, "Y"));
3481 
3482  if (mbs_eql (descriptor, "y"))
3483  {
3484  sprintf (year_string, "%02d", year % 100);
3485  }
3486  else
3487  {
3488  sprintf (year_string, "%d", year);
3489  }
3490  assert (strlen (year_string) < sizeof year_string);
3491 
3492  return year_string;
3493 }
3494 
3495 /*
3496  * fmt_month_string() - Return a string representing the month of the given
3497  * date, according to the given format descriptor.
3498  * return:
3499  * the_date(in) :
3500  * descriptor(in) :
3501  */
3502 static const char *
3503 fmt_month_string (int month, const char *descriptor)
3504 {
3505  const char *month_string = NULL;
3506 
3507  assert (mbs_eql (descriptor, "b") || mbs_eql (descriptor, "B") || mbs_eql (descriptor, "m"));
3508 
3509  if (mbs_eql (descriptor, "b"))
3510  {
3511  month_string = local_short_month_name (month - 1);
3512  }
3513  else if (mbs_eql (descriptor, "B"))
3514  {
3515  month_string = local_long_month_name (month - 1);
3516  }
3517  else /* if (mbs_eql (descriptor, "m")) */
3518  {
3519  static char month_number[2 * MB_LEN_MAX + 1];
3520  sprintf (month_number, "%02d", month);
3521  assert (strlen (month_number) < sizeof month_number);
3522  month_string = month_number;
3523  }
3524 
3525  return month_string;
3526 }
3527 
3528 /*
3529  * fmt_monthday_string() - Return a string representing the month day of
3530  * the given date, according to the given format descriptor.
3531  * return:
3532  * the_date(in) :
3533  * descriptor(in) :
3534  */
3535 static const char *
3536 fmt_monthday_string (int day, const char *descriptor)
3537 {
3538  static char day_number[2 * MB_LEN_MAX + 1];
3539 
3540  assert (mbs_eql (descriptor, "d") || mbs_eql (descriptor, "e"));
3541 
3542  sprintf (day_number, mbs_eql (descriptor, "d") ? "%02d" : "%2d", day);
3543  assert (strlen (day_number) < sizeof day_number);
3544 
3545  return day_number;
3546 }
3547 
3548 /*
3549  * fmt_weekday_string() - Return a string representing the week day of the
3550  * given date, according to the given format descriptor.
3551  * return:
3552  * the_date(in) :
3553  * descriptor(in) :
3554  */
3555 static const char *
3556 fmt_weekday_string (int weekday, const char *descriptor)
3557 {
3558  const char *day_string = NULL;
3559 
3560  assert (mbs_eql (descriptor, "a") || mbs_eql (descriptor, "A") || mbs_eql (descriptor, "w"));
3561 
3562  if (mbs_eql (descriptor, "a"))
3563  {
3564  day_string = local_short_weekday_name (weekday);
3565  }
3566  else if (mbs_eql (descriptor, "A"))
3567  {
3568  day_string = local_long_weekday_name (weekday);
3569  }
3570  else /* if (mbs_eql (descriptor, "w")) */
3571  {
3572  static char day_number[MB_LEN_MAX + 1];
3573  sprintf (day_number, "%d", weekday);
3574  assert (strlen (day_number) < sizeof day_number);
3575  day_string = day_number;
3576  }
3577 
3578  return day_string;
3579 }
3580 #endif
3581 
3582 /*
3583  * fmt_date_value() - Scan tokens and parse a date value according to given
3584  * format descriptor. If a valid value can't be found, then return an error
3585  * condition. otherwise, set the_month, the_day, and the_year to the
3586  * value found.
3587  * return:
3588  * descriptor(in) :
3589  * the_month(out) :
3590  * the_day(out) :
3591  * the_year(out) :
3592  */
3593 static int
3594 fmt_date_value (const char *descriptor, int *the_month, int *the_day, int *the_year)
3595 {
3596  bool bad_value = false;
3597  int error = 0;
3598 
3599  assert (mbs_eql (descriptor, "D") || mbs_eql (descriptor, "x") || mbs_eql (descriptor, "E"));
3600 
3601 #if defined (ENABLE_UNUSED_FUNCTION)
3602  if (mbs_eql (descriptor, "D"))
3603  {
3604  do
3605  {
3606  FMT_TOKEN token;
3607 
3608  error = fmt_month_value ("m", the_month);
3609  if (error)
3610  {
3611  break;
3612  }
3613 
3614  bad_value = cnv_fmt_lex (&token) != FT_DATE_SEPARATOR;
3615  if (bad_value)
3616  {
3617  break;
3618  }
3619 
3620  error = fmt_monthday_value ("d", the_day);
3621  if (error)
3622  {
3623  break;
3624  }
3625 
3626  bad_value = cnv_fmt_lex (&token) != FT_DATE_SEPARATOR;
3627  if (bad_value)
3628  {
3629  break;
3630  }
3631 
3632  error = fmt_year_value ("y", the_year);
3633  }
3634  while (0);
3635  }
3636 
3637  else
3638 #endif
3639 
3640  if (mbs_eql (descriptor, "x"))
3641  {
3642  error = local_date_value (the_month, the_day, the_year);
3643  }
3644 
3645 #if defined (ENABLE_UNUSED_FUNCTION)
3646  else if (mbs_eql (descriptor, "E"))
3647  {
3648  error = local_alt_date_value (the_month, the_day, the_year);
3649  }
3650 #endif
3651 
3652  if (bad_value)
3653  {
3654  error = CNV_ERR_BAD_DATE;
3655  co_signal (error, CNV_ER_FMT_BAD_DATE, descriptor);
3656  }
3657 
3658  return error;
3659 }
3660 
3661 #if defined (ENABLE_UNUSED_FUNCTION)
3662 /*
3663  * fmt_year_value() - Scan tokens and parse a year value according to given
3664  * format descriptor. If a valid value can't be found, then return an error
3665  * condition. otherwise, set the_year to the value found.
3666  * return:
3667  * descriptor(in) :
3668  * the_year(in/out) :
3669  *
3670  * note : if the string represents the year only within the century
3671  * (i.e. 00-99), the input value of the_year is used to determine the
3672  * century.
3673  */
3674 static int
3675 fmt_year_value (const char *descriptor, int *the_year)
3676 {
3677  bool bad_value = false;
3678  int error = 0;
3679  FMT_TOKEN token;
3680  FMT_TOKEN_TYPE type;
3681 
3682  assert (mbs_eql (descriptor, "y") || mbs_eql (descriptor, "Y"));
3683 
3684  if (mbs_eql (descriptor, "Y"))
3685  {
3686  type = cnv_fmt_lex (&token);
3687  bad_value = !(type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY) || (*the_year = atoi (token.text)) == 0;
3688  }
3689 
3690  else if (mbs_eql (descriptor, "y"))
3691  {
3692  type = cnv_fmt_lex (&token);
3693  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS);
3694  if (!bad_value)
3695  {
3696  int yr = atoi (token.text);
3697  *the_year = (*the_year / 100) * 100 + (*the_year > 0 ? yr : -yr);
3698  }
3699  }
3700 
3701  if (bad_value)
3702  {
3703  error = CNV_ERR_BAD_YEAR;
3704  co_signal (error, CNV_ER_FMT_BAD_YEAR, descriptor);
3705  }
3706 
3707  return error;
3708 }
3709 
3710 /*
3711  * fmt_month_value() - set into the_month out variable with the month (1-12)
3712  * represented by the given string and format descriptor.
3713  * If a format error occurs return error code.
3714  * return: error code
3715  * descriptor(in) :
3716  * the_month(out) :
3717  */
3718 static int
3719 fmt_month_value (const char *descriptor, int *the_month)
3720 {
3721  bool bad_value = false;
3722  int error = 0;
3723  FMT_TOKEN token;
3724  FMT_TOKEN_TYPE type;
3725 
3726  assert (mbs_eql (descriptor, "b") || mbs_eql (descriptor, "B") || mbs_eql (descriptor, "m"));
3727 
3728  if (mbs_eql (descriptor, "b"))
3729  {
3730  type = cnv_fmt_lex (&token);
3731 
3732  /* Careful: long/short names for May are the same! */
3733  bad_value = !(type == FT_MONTH || (type == FT_MONTH_LONG && token.value == 5));
3734  if (!bad_value)
3735  {
3736  *the_month = token.value;
3737  }
3738  }
3739 
3740  else if (mbs_eql (descriptor, "B"))
3741  {
3742  bad_value = cnv_fmt_lex (&token) != FT_MONTH_LONG;
3743  if (!bad_value)
3744  {
3745  *the_month = token.value;
3746  }
3747  }
3748 
3749  else if (mbs_eql (descriptor, "m"))
3750  {
3751  type = cnv_fmt_lex (&token);
3752  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS) || (*the_month = atoi (token.text)) > 12
3753  || *the_month < 1;
3754  }
3755 
3756  if (bad_value)
3757  {
3758  error = CNV_ERR_BAD_MONTH;
3759  co_signal (error, CNV_ER_FMT_BAD_MONTH, descriptor);
3760  }
3761  return error;
3762 }
3763 
3764 /*
3765  * fmt_monthday_value() - Scan tokens and parse a monthday value (1-31)
3766  * according to given format descriptor. If a valid value can't be
3767  * found, then return an error condition.
3768  * otherwise, set the_day to the value found.
3769  * return:
3770  * descriptor(in) :
3771  * the_day(out) :
3772  */
3773 static int
3774 fmt_monthday_value (const char *descriptor, int *the_day)
3775 {
3776  int error = 0;
3777  FMT_TOKEN token;
3778  FMT_TOKEN_TYPE type;
3779 
3780  assert (mbs_eql (descriptor, "d") || mbs_eql (descriptor, "e"));
3781 
3782  type = cnv_fmt_lex (&token);
3783  if (!(type == FT_TIME_DIGITS || type == (mbs_eql (descriptor, "d") ? FT_TIME_DIGITS_0 : FT_TIME_DIGITS_BLANK))
3784  || (*the_day = atoi (token.text)) > 31 || *the_day < 1)
3785  {
3786  error = CNV_ERR_BAD_MDAY;
3787  co_signal (error, CNV_ER_FMT_BAD_MDAY, descriptor);
3788  }
3789 
3790  return error;
3791 }
3792 
3793 /*
3794  * fmt_weekday_value() - Scan tokens and parse a weekday value (0-6) according
3795  * to given format descriptor. If a valid value can't be found, then return
3796  * an error condition. otherwise, set the_day to the value found.
3797  * return:
3798  * descriptor(in) :
3799  * the_day(out) :
3800  */
3801 static int
3802 fmt_weekday_value (const char *descriptor, int *the_day)
3803 {
3804  bool bad_value = false;
3805  int error = 0;
3806  FMT_TOKEN token;
3807 
3808  assert (mbs_eql (descriptor, "a") || mbs_eql (descriptor, "A") || mbs_eql (descriptor, "w"));
3809 
3810  if (mbs_eql (descriptor, "a"))
3811  {
3812  bad_value = cnv_fmt_lex (&token) != FT_WEEKDAY;
3813  if (!bad_value)
3814  {
3815  *the_day = token.value;
3816  }
3817  }
3818 
3819  else if (mbs_eql (descriptor, "A"))
3820  {
3821  bad_value = cnv_fmt_lex (&token) != FT_WEEKDAY_LONG;
3822  if (!bad_value)
3823  {
3824  *the_day = token.value;
3825  }
3826  }
3827 
3828  else if (mbs_eql (descriptor, "w"))
3829  {
3830  bad_value = cnv_fmt_lex (&token) != FT_TIME_DIGITS_ANY || (*the_day = atoi (token.text)) > 6;
3831  }
3832 
3833  if (bad_value)
3834  {
3835  error = CNV_ERR_BAD_WDAY;
3836  co_signal (error, CNV_ER_FMT_BAD_WDAY, descriptor);
3837  }
3838  return error;
3839 }
3840 
3841 /*
3842  * fmt_weekday_date() - Return the date for the given weekday that is in the
3843  * same week as the given month/day/year. For example, if the given date
3844  * is 11/5/93 and the given weekday is Monday, then the date returned will
3845  * be 11/1/93.
3846  * return:
3847  * month(in) :
3848  * day(in) :
3849  * year(in) :
3850  * weekday(in) :
3851  */
3852 static DB_DATE
3853 fmt_weekday_date (int month, int day, int year, int weekday)
3854 {
3855  DB_DATE new_date;
3856  db_date_encode (&new_date, month, day, year);
3857 
3858  return new_date - db_date_weekday (&new_date) + weekday;
3859 }
3860 #endif
3861 
3862 /*
3863  * fmt_time_string() - Return a string representing the given time, according
3864  * to the given format descriptor.
3865  * return:
3866  * the_time(in) :
3867  * descriptor(in) :
3868  */
3869 static const char *
3870 fmt_time_string (const DB_TIME * the_time, const char *descriptor)
3871 {
3872 #if defined (ENABLE_UNUSED_FUNCTION)
3873  static char time_string[FMT_MAX_TIME_STRING * MB_LEN_MAX + 1];
3874 #endif
3875  const char *string = NULL;
3876 
3877  assert (mbs_eql (descriptor, "R") || mbs_eql (descriptor, "r") || mbs_eql (descriptor, "T")
3878  || mbs_eql (descriptor, "X"));
3879 
3880 #if defined (ENABLE_UNUSED_FUNCTION)
3881  if (mbs_eql (descriptor, "T"))
3882  {
3883  sprintf (time_string, "%s%s%s%s%s", fmt_hour_string (the_time, "H"), LOCAL_COLON,
3884  fmt_minute_string (the_time, "M"), LOCAL_COLON, fmt_second_string (the_time, "S"));
3885  assert (strlen (time_string) < sizeof time_string);
3886  string = time_string;
3887  }
3888  else
3889 #endif
3890  if (mbs_eql (descriptor, "X"))
3891  {
3892  string = local_time_string (the_time);
3893  }
3894 #if defined (ENABLE_UNUSED_FUNCTION)
3895  else if (mbs_eql (descriptor, "r"))
3896  {
3897  sprintf (time_string, "%s%s%s%s%s%s%s", fmt_hour_string (the_time, "I"), LOCAL_COLON,
3898  fmt_minute_string (the_time, "M"), LOCAL_COLON, fmt_second_string (the_time, "S"), LOCAL_SPACE,
3899  local_am_pm_string (the_time));
3900  assert (strlen (time_string) < sizeof time_string);
3901  string = time_string;
3902  }
3903 
3904  else if (mbs_eql (descriptor, "R"))
3905  {
3906  sprintf (time_string, "%s%s%s", fmt_hour_string (the_time, "H"), LOCAL_COLON, fmt_minute_string (the_time, "M"));
3907  assert (strlen (time_string) < sizeof time_string);
3908  string = time_string;
3909  }
3910 #endif
3911  return string;
3912 }
3913 
3914 /*
3915  * fmt_time_value() - Scan tokens and parse a time value according to given
3916  * format descriptor. If a valid value can't be found, then return an error
3917  * condition. otherwise, set the_hour, the_min, and the_sec to the
3918  * value found.
3919  * return:
3920  * descriptor(in) :
3921  * the_hour(out) :
3922  * the_min(out) :
3923  * the_sec(out) :
3924  */
3925 static int
3926 fmt_time_value (const char *descriptor, int *the_hour, int *the_min, int *the_sec)
3927 {
3928  bool bad_value = false;
3929  int error = 0;
3930 #if defined (ENABLE_UNUSED_FUNCTION)
3931  FMT_TOKEN token;
3932 #endif
3933 
3934  assert (mbs_eql (descriptor, "R") || mbs_eql (descriptor, "r") || mbs_eql (descriptor, "T")
3935  || mbs_eql (descriptor, "X"));
3936 
3937 #if defined (ENABLE_UNUSED_FUNCTION)
3938  if (mbs_eql (descriptor, "T"))
3939  {
3940  do
3941  {
3942  error = fmt_hour_value ("H", the_hour);
3943  if (error)
3944  {
3945  break;
3946  }
3947 
3948  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
3949  if (bad_value)
3950  {
3951  break;
3952  }
3953 
3954  error = fmt_minute_value ("M", the_min);
3955  if (error)
3956  {
3957  break;
3958  }
3959 
3960  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
3961  if (bad_value)
3962  {
3963  break;
3964  }
3965 
3966  error = fmt_second_value ("S", the_sec);
3967  }
3968  while (0);
3969  }
3970 
3971  else
3972 #endif
3973  if (mbs_eql (descriptor, "X"))
3974  {
3975  error = local_time_value (the_hour, the_min, the_sec);
3976  }
3977 
3978 #if defined (ENABLE_UNUSED_FUNCTION)
3979  else if (mbs_eql (descriptor, "r"))
3980  {
3981  do
3982  {
3983  bool pm;
3984 
3985  error = fmt_hour_value ("I", the_hour);
3986  if (error)
3987  {
3988  break;
3989  }
3990 
3991  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
3992  if (bad_value)
3993  {
3994  break;
3995  }
3996 
3997  error = fmt_minute_value ("M", the_min);
3998  if (error)
3999  {
4000  break;
4001  }
4002 
4003  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
4004  if (bad_value)
4005  {
4006  break;
4007  }
4008 
4009  error = fmt_second_value ("S", the_sec);
4010  if (error)
4011  {
4012  break;
4013  }
4014 
4015  /* Skip blank "pattern" character. */
4016  bad_value = strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE));
4017  if (bad_value)
4018  {
4019  break;
4020  }
4022 
4023  error = local_am_pm_value (&pm);
4024  if (error)
4025  {
4026  break;
4027  }
4028 
4029  *the_hour %= 12;
4030  if (pm)
4031  *the_hour += 12;
4032  }
4033  while (0);
4034  }
4035 
4036  else if (mbs_eql (descriptor, "R"))
4037  {
4038  do
4039  {
4040  error = fmt_hour_value ("H", the_hour);
4041  if (error)
4042  {
4043  break;
4044  }
4045 
4046  bad_value = cnv_fmt_lex (&token) != FT_TIME_SEPARATOR;
4047  if (bad_value)
4048  {
4049  break;
4050  }
4051 
4052  error = fmt_minute_value ("M", the_min);
4053  }
4054  while (0);
4055  }
4056 #endif
4057 
4058  if (bad_value)
4059  {
4060  error = CNV_ERR_BAD_TIME;
4061  co_signal (error, CNV_ER_FMT_BAD_TIME, descriptor);
4062  }
4063 
4064  return error;
4065 }
4066 
4067 #if defined (ENABLE_UNUSED_FUNCTION)
4068 /*
4069  * fmt_hour_string() - Return a string representing the hour of the given time,
4070  * according to the given format descriptor.
4071  * return:
4072  * the_time(in) :
4073  * descriptor(in) :
4074  */
4075 static const char *
4076 fmt_hour_string (const DB_TIME * the_time, const char *descriptor)
4077 {
4078  static char hour_string[2 * MB_LEN_MAX + 1];
4079  int hour, min, sec;
4080 
4081  assert (mbs_eql (descriptor, "H") || mbs_eql (descriptor, "I") || mbs_eql (descriptor, "k")
4082  || mbs_eql (descriptor, "l"));
4083 
4084  db_time_decode ((DB_TIME *) the_time, &hour, &min, &sec);
4085 
4086  sprintf (hour_string, mbs_eql (descriptor, "k")
4087  || mbs_eql (descriptor, "l") ? "%2d" : "%02d", mbs_eql (descriptor, "I")
4088  || mbs_eql (descriptor, "l") ? (hour ? hour % 12 : 12) : hour);
4089  assert (strlen (hour_string) < sizeof hour_string);
4090 
4091  return hour_string;
4092 }
4093 
4094 /*
4095  * fmt_hour_value() - Scan tokens and parse an hour value according to given
4096  * format descriptor. If a valid value can't be found, then return an error
4097  * condition. otherwise, set the_hour to the value found.
4098  * return:
4099  * descriptor(in) :
4100  * the_hour(out) :
4101  */
4102 static int
4103 fmt_hour_value (const char *descriptor, int *the_hour)
4104 {
4105  bool bad_value = false;
4106  int error = 0;
4107  FMT_TOKEN token;
4108  FMT_TOKEN_TYPE type;
4109 
4110  assert (mbs_eql (descriptor, "H") || mbs_eql (descriptor, "I") || mbs_eql (descriptor, "k")
4111  || mbs_eql (descriptor, "l"));
4112 
4113  if (mbs_eql (descriptor, "H"))
4114  {
4115  type = cnv_fmt_lex (&token);
4116  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS) || (*the_hour = atoi (token.text)) > 23;
4117  }
4118 
4119  else if (mbs_eql (descriptor, "I"))
4120  {
4121  type = cnv_fmt_lex (&token);
4122  bad_value = !(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS) || (*the_hour = atoi (token.text)) > 12
4123  || *the_hour < 1;
4124  }
4125 
4126  else if (mbs_eql (descriptor, "k"))
4127  {
4128  type = cnv_fmt_lex (&token);
4129  bad_value = !(type == FT_TIME_DIGITS_BLANK || type == FT_TIME_DIGITS) || (*the_hour = atoi (token.text)) > 23;
4130  }
4131 
4132  else if (mbs_eql (descriptor, "l"))
4133  {
4134  type = cnv_fmt_lex (&token);
4135  bad_value = !(type == FT_TIME_DIGITS_BLANK || type == FT_TIME_DIGITS) || (*the_hour = atoi (token.text)) > 12
4136  || *the_hour < 1;
4137  }
4138 
4139  if (bad_value)
4140  {
4141  error = CNV_ERR_BAD_HOUR;
4142  co_signal (error, CNV_ER_FMT_BAD_HOUR, descriptor);
4143  }
4144 
4145  return error;
4146 }
4147 
4148 /*
4149  * fmt_minute_string() - Return a string representing the minute of the given
4150  * time, according to the given format descriptor.
4151  * return:
4152  * the_time(in) :
4153  * descriptor(in) :
4154  */
4155 static const char *
4156 fmt_minute_string (const DB_TIME * the_time, const char *descriptor)
4157 {
4158  static char min_string[2 * MB_LEN_MAX + 1];
4159  int hour, min, sec;
4160 
4161  assert (mbs_eql (descriptor, "M"));
4162 
4163  db_time_decode ((DB_TIME *) the_time, &hour, &min, &sec);
4164 
4165  sprintf (min_string, "%02d", min);
4166  assert (strlen (min_string) < sizeof min_string);
4167 
4168  return min_string;
4169 }
4170 #endif
4171 
4172 /*
4173  * fmt_minute_value() - Scan tokens and parse a minute value according
4174  * to given format descriptor. If a valid value can't be found, then
4175  * return an error condition. otherwise, set the_min to the value found.
4176  * return:
4177  * descriptor(in) :
4178  * the_min(out) :
4179  */
4180 static int
4181 fmt_minute_value (const char *descriptor, int *the_min)
4182 {
4183  int error = 0;
4184  FMT_TOKEN token;
4185  FMT_TOKEN_TYPE type;
4186 
4187  assert (mbs_eql (descriptor, "M"));
4188 
4189  type = cnv_fmt_lex (&token);
4190  if (!(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY)
4191  || (*the_min = atoi (token.text)) > 59)
4192  {
4193  error = CNV_ERR_BAD_MIN;
4194  co_signal (error, CNV_ER_FMT_BAD_MIN, descriptor);
4195  }
4196 
4197  return error;
4198 }
4199 
4200 #if defined (ENABLE_UNUSED_FUNCTION)
4201 /*
4202  * fmt_second_string() - Return a string representing the second of the given
4203  * time, according to the given format descriptor.
4204  * return:
4205  * the_time(in) :
4206  * descriptor(in) :
4207  */
4208 static const char *
4209 fmt_second_string (const DB_TIME * the_time, const char *descriptor)
4210 {
4211  static char sec_string[2 * MB_LEN_MAX + 1];
4212  int hour, min, sec;
4213 
4214  assert (mbs_eql (descriptor, "S"));
4215 
4216  db_time_decode ((DB_TIME *) the_time, &hour, &min, &sec);
4217 
4218  sprintf (sec_string, "%02d", sec);
4219  assert (strlen (sec_string) < sizeof sec_string);
4220 
4221  return sec_string;
4222 }
4223 #endif
4224 
4225 /*
4226  * fmt_second_value() - Scan tokens and parse a seconds value according
4227  * to given format descriptor. If a valid value can't be found, then
4228  * return an error condition. otherwise, set the_sec to the value found.
4229  * return:
4230  * descriptor(in) :
4231  * the_sec(out) :
4232  */
4233 static int
4234 fmt_second_value (const char *descriptor, int *the_sec)
4235 {
4236  int error = 0;
4237  FMT_TOKEN token;
4238  FMT_TOKEN_TYPE type;
4239 
4240  assert (mbs_eql (descriptor, "S"));
4241 
4242  type = cnv_fmt_lex (&token);
4243  if (!(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY)
4244  || (*the_sec = atoi (token.text)) > 59)
4245  {
4246  error = CNV_ERR_BAD_SEC;
4247  co_signal (error, CNV_ER_FMT_BAD_SEC, descriptor);
4248  }
4249 
4250  return error;
4251 }
4252 
4253 #if defined (ENABLE_UNUSED_FUNCTION)
4254 /*
4255  * fmt_millisecond_value() - Scan tokens and parse a seconds value according
4256  * to given format descriptor. If a valid value can't be found, then
4257  * return an error condition. otherwise, set the_sec to the value found.
4258  * return:
4259  * descriptor(in) :
4260  * the_sec(out) :
4261  */
4262 static int
4263 fmt_millisecond_value (const char *descriptor, int *the_msec)
4264 {
4265  int error = 0;
4266  FMT_TOKEN token;
4267  FMT_TOKEN_TYPE type;
4268 
4269  assert (mbs_eql (descriptor, "MS"));
4270 
4271  type = cnv_fmt_lex (&token);
4272  if (!(type == FT_TIME_DIGITS_0 || type == FT_TIME_DIGITS || type == FT_TIME_DIGITS_ANY)
4273  || (*the_msec = atoi (token.text)) > 999)
4274  {
4275  error = CNV_ERR_BAD_MSEC;
4276  co_signal (error, CNV_ER_FMT_BAD_MSEC, descriptor);
4277  }
4278 
4279  return error;
4280 }
4281 #endif
4282 
4283 /*
4284  * fmt_timestamp_string() - Return a string representing the given timestamp,
4285  * according to the given format descriptor.
4286  * return:
4287  * the_timestamp(in) :
4288  * descriptor(in) :
4289  */
4290 static const char *
4291 fmt_timestamp_string (const DB_TIMESTAMP * the_timestamp, const char *descriptor)
4292 {
4293  DB_DATE the_date;
4294  DB_TIME the_time;
4295  const char *string = NULL;
4296 
4297  assert (mbs_eql (descriptor, "c") || mbs_eql (descriptor, "C"));
4298 
4299  (void) db_timestamp_decode_ses ((DB_TIMESTAMP *) the_timestamp, &the_date, &the_time);
4300 
4301  if (mbs_eql (descriptor, "c"))
4302  {
4303  static char timestamp_string[FMT_MAX_TIMESTAMP_STRING * MB_LEN_MAX + 1];
4304 
4305  sprintf (timestamp_string, "%s%s%s", fmt_date_string (&the_date, "x"), LOCAL_SPACE,
4306  fmt_time_string (&the_time, "X"));
4307  assert (strlen (timestamp_string) < (int) sizeof (timestamp_string));
4308  string = timestamp_string;
4309  }
4310 #if defined (ENABLE_UNUSED_FUNCTION)
4311  else if (mbs_eql (descriptor, "C"))
4312  {
4313  string = local_timestamp_string (the_timestamp);
4314  }
4315 #endif
4316  return string;
4317 }
4318 
4319 /*
4320  * fmt_timestamp_value() - Scan tokens and parse timestamp value according
4321  * to given format descriptor. If a valid value can't be found, then return
4322  * an error condition. otherwise, set the_day, the_month, the_year, the_hour
4323  * (0-23), the_min, and the_sec to the value found.
4324  * return:
4325  * descriptor(in) :
4326  * the_month(out) :
4327  * the_day(out) :
4328  * the_year(out) :
4329  * the_hour(out) :
4330  * the_min(out) :
4331  * the_sec(out) :
4332  */
4333 static int
4334 fmt_timestamp_value (const char *descriptor, int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min,
4335  int *the_sec)
4336 {
4337  bool bad_value = false;
4338  int error = 0;
4339 
4340  assert (mbs_eql (descriptor, "c") || mbs_eql (descriptor, "C"));
4341 
4342  if (mbs_eql (descriptor, "c"))
4343  {
4344  do
4345  {
4346  error = fmt_date_value ("x", the_month, the_day, the_year);
4347  if (error)
4348  {
4349  break;
4350  }
4351 
4352  /* Skip blank "pattern" character. */
4353  bad_value = strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE));
4354  if (bad_value)
4355  {
4356  break;
4357  }
4359 
4360  error = fmt_time_value ("X", the_hour, the_min, the_sec);
4361  }
4362  while (0);
4363  }
4364 
4365 #if defined (ENABLE_UNUSED_FUNCTION)
4366  else if (mbs_eql (descriptor, "C"))
4367  {
4368  error = local_timestamp_value (the_month, the_day, the_year, the_hour, the_min, the_sec);
4369  }
4370 #endif
4371 
4372  if (bad_value)
4373  {
4374  error = CNV_ERR_BAD_TIMESTAMP;
4375  co_signal (error, CNV_ER_FMT_BAD_TIMESTAMP, descriptor);
4376  }
4377 
4378  return error;
4379 }
4380 
4381 #if defined(ENABLE_UNUSED_FUNCTION)
4382 /*
4383  * fmt_datetime_string() -
4384  * return:
4385  * the_timestamp(in) :
4386  * descriptor(in) :
4387  */
4388 static const char *
4389 fmt_datetime_string (const DB_DATETIME * the_datetime, const char *descriptor)
4390 {
4391  int months, days, years;
4392  int hours, minutes, seconds, milliseconds;
4393  const char *string = NULL;
4394 
4395  assert (mbs_eql (descriptor, "c") || mbs_eql (descriptor, "C"));
4396 
4397  db_datetime_decode ((DB_DATETIME *) the_datetime, &months, &days, &years, &hours, &minutes, &seconds, &milliseconds);
4398 
4399  if (mbs_eql (descriptor, "c"))
4400  {
4401  static char datetime_string[FMT_MAX_DATETIME_STRING * MB_LEN_MAX + 1];
4402 
4403  sprintf (datetime_string, "%d/%d/%d %d:%d:%d.%d", months, days, years, hours, minutes, seconds, milliseconds);
4404  string = datetime_string;
4405  }
4406  else if (mbs_eql (descriptor, "C"))
4407  {
4408  string = local_datetime_string (the_datetime);
4409  }
4410 
4411  return string;
4412 }
4413 
4414 /*
4415  * fmt_timestamp_value() - Scan tokens and parse timestamp value according
4416  * to given format descriptor. If a valid value can't be found, then return
4417  * an error condition. otherwise, set the_day, the_month, the_year, the_hour
4418  * (0-23), the_min, and the_sec to the value found.
4419  * return:
4420  * descriptor(in) :
4421  * the_month(out) :
4422  * the_day(out) :
4423  * the_year(out) :
4424  * the_hour(out) :
4425  * the_min(out) :
4426  * the_sec(out) :
4427  */
4428 static int
4429 fmt_datetime_value (const char *descriptor, int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min,
4430  int *the_sec, int *the_msec)
4431 {
4432  bool bad_value = false;
4433  int error = 0;
4434  assert (mbs_eql (descriptor, "c") || mbs_eql (descriptor, "C"));
4435  if (mbs_eql (descriptor, "c"))
4436  {
4437  do
4438  {
4439  error = fmt_date_value ("x", the_month, the_day, the_year);
4440  if (error)
4441  {
4442  break;
4443  }
4444 
4445  /* Skip blank "pattern" character. */
4446  bad_value = strncmp (cnv_fmt_next_token (), LOCAL_SPACE, strlen (LOCAL_SPACE));
4447  if (bad_value)
4448  {
4449  break;
4450  }
4452  error = fmt_time_value ("X", the_hour, the_min, the_sec);
4453  }
4454  while (0);
4455  }
4456 
4457  else if (mbs_eql (descriptor, "C"))
4458  {
4459  error = local_timestamp_value (the_month, the_day, the_year, the_hour, the_min, the_sec);
4460  }
4461 
4462  if (bad_value)
4463  {
4464  error = CNV_ERR_BAD_TIMESTAMP;
4465  co_signal (error, CNV_ER_FMT_BAD_TIMESTAMP, descriptor);
4466  }
4467 
4468  return error;
4469 }
4470 #endif /* ENABLE_UNUSED_FUNCTION */
4471 
4472 /*
4473  * tfmt_new() - Converts a date/time/timestamp format string into an array of
4474  * tokens. The token array is terminated by a token of type FT_NONE.
4475  * return:
4476  * format(in) :
4477  */
4478 static const FMT_TOKEN *
4479 tfmt_new (const char *format)
4480 {
4481  static ADJ_ARRAY *tokens = NULL;
4482  static ADJ_ARRAY *strings = NULL;
4483 
4484  FMT_TOKEN token;
4485  FMT_TOKEN_TYPE type;
4486  FMT_TOKEN *t;
4487  const char *string;
4488 
4489  assert (format);
4490 
4491  /*
4492  * Initialize arrays for tokens and token strings. We must copy all token
4493  * strings, because the token.text pointer is reused when the next token
4494  * is scanned.
4495  */
4496  if (!tokens)
4497  {
4498  tokens = adj_ar_new (sizeof (FMT_TOKEN), 2, 2.0);
4499  strings = adj_ar_new (1, 0, 2.0);
4500  }
4501  adj_ar_remove (tokens, 0, ADJ_AR_EOA);
4502  adj_ar_remove (strings, 0, ADJ_AR_EOA);
4503 
4504  /* Scan format string for tokens. */
4505  for (cnv_fmt_analyze (format, FL_TIME_FORMAT);
4506  (type = cnv_fmt_lex (&token), adj_ar_append (tokens, &token, 1), type != FT_NONE);)
4507  {
4508  /* Preserve a copy of token string. */
4509  adj_ar_append (strings, token.text, token.length + 1);
4510  }
4511 
4512  /* Update tokens to point to string copies. */
4513  for (t = (FMT_TOKEN *) adj_ar_get_buffer (tokens), string = (const char *) adj_ar_get_buffer (strings);
4514  t->type != FT_NONE; string += t->length + 1, t++)
4515  {
4516  t->text = string;
4517  }
4518 
4519  return (FMT_TOKEN *) adj_ar_get_buffer (tokens);
4520 }
4521 
4522 /*
4523  * Float Format Descriptor Functions
4524  */
4525 
4526 /*
4527  * ffmt_valid_char() - Return true if token chars can legally appear in
4528  * a float value string.
4529  * return:
4530  * token(in) :
4531  */
4532 static bool
4534 {
4535  FMT_TOKEN_TYPE type = token->type;
4536 
4537  return type == FT_NUMBER || type == FT_ZEROES || type == FT_MINUS || type == FT_PLUS || type == FT_STARS
4538  || type == FT_DECIMAL || type == FT_THOUSANDS || mbs_eql (token->text, local_thousands ());
4539 }
4540 
4541 /*
4542  * ffmt_new() - Initialize a descriptor for the given float format string.
4543  * return:
4544  * ffmt(in) :
4545  * format(in) :
4546  */
4547 static void
4548 ffmt_new (FLOAT_FORMAT * ffmt, const char *format)
4549 {
4550  wchar_t idc[3];
4551  const wchar_t *wfmt = cnv_wcs (format);
4552  const wchar_t *fraction_part = wcsstr (wfmt, FMT_DECIMAL ());
4553  const wchar_t *integer_part = wcsstr (wfmt, FMT_PLUS ());
4554 
4555  ffmt->scientific = wcsstr (wfmt, FMT_SCIENTIFIC ()) != NULL;
4556  ffmt->thousands = wcsstr (wfmt, FMT_THOUSANDS ()) != NULL;
4557 
4558  if (fraction_part)
4559  {
4560  fraction_part++;
4561  }
4562  ffmt->decimal = (fraction_part != NULL || !wcslen (wfmt));
4563 
4564  ffmt->fractional_type = DIGIT_Z;
4565  ffmt->fractional_digits = (fraction_part ? wcsspn (fraction_part, FMT_Z ()) : 0);
4566  if (fraction_part && !ffmt->fractional_digits)
4567  {
4568  ffmt->fractional_digits = wcsspn (fraction_part, FMT_9 ());
4569  if (ffmt->fractional_digits)
4570  {
4571  ffmt->fractional_type = DIGIT_9;
4572  }
4573  else
4574  {
4575  ffmt->fractional_digits = wcsspn (fraction_part, FMT_STAR ());
4576  if (ffmt->fractional_digits)
4577  {
4578  ffmt->fractional_type = DIGIT_STAR;
4579  }
4580  else
4581  {
4582  ffmt->fractional_type = DIGIT_Z;
4583  }
4584  }
4585  }
4586 
4587  integer_part = integer_part ? integer_part + 1 : wfmt;
4588  ffmt->sign_required = integer_part != wfmt;
4589 
4590  ffmt->integral_type = DIGIT_Z;
4591  ffmt->integral_digits = wcsspn (integer_part, WCSCAT (idc, FMT_Z (), FMT_THOUSANDS ())) - ffmt->thousands;
4592  if (ffmt->integral_digits <= 0)
4593  {
4594  ffmt->integral_digits = wcsspn (integer_part, WCSCAT (idc, FMT_9 (), FMT_THOUSANDS ())) - ffmt->thousands;
4595  if (ffmt->integral_digits > 0)
4596  {
4597  ffmt->integral_type = DIGIT_9;
4598  }
4599  else
4600  {
4601  ffmt->integral_digits = wcsspn (integer_part, WCSCAT (idc, FMT_STAR (), FMT_THOUSANDS ())) - ffmt->thousands;
4602  if (ffmt->integral_digits > 0)
4603  {
4604  ffmt->integral_type = DIGIT_STAR;
4605  }
4606  else
4607  {
4608  ffmt->integral_type = DIGIT_Z;
4609  }
4610  }
4611  }
4612 }
4613 
4614 /*
4615  * ffmt_value() - Get the double value represented by the value string.
4616  * Return a pointer to the first char of the string after the last value
4617  * char. If an error occurs, then the value is unchanged and NULL is
4618  * returned.
4619  * return:
4620  * ffmt(in) :
4621  * string(in) :
4622  * the_double(out) :
4623  */
4624 static const char *
4625 ffmt_value (FLOAT_FORMAT * ffmt, const char *string, double *the_double)
4626 {
4627  int error = 0;
4628  FMT_TOKEN token;
4629  FMT_TOKEN_TYPE type;
4630  bool decimal_missing = false;
4631 
4632  cnv_fmt_analyze (string, FL_LOCAL_NUMBER);
4633 
4634  do
4635  {
4636  /* Get value of integer part. */
4637  error =
4639  the_double);
4640 
4641  if (error && error != CNV_ERR_MISSING_INTEGER)
4642  {
4643  break;
4644  }
4645 
4646  type = cnv_fmt_lex (&token);
4647 
4648  if (ffmt->decimal)
4649  {
4650  /* Decimal point found? */
4651  decimal_missing = (type != FT_DECIMAL);
4652  if (!decimal_missing)
4653  {
4654  double fraction_part;
4655 
4656  if (error)
4657  {
4658  break; /* integer digit really missing. */
4659  }
4660 
4661  /* Yes, get value of fraction part. */
4662  error = fmt_fractional_value (ffmt->fractional_type, ffmt->fractional_digits, &fraction_part);
4663 
4664  if (error && error != CNV_ERR_MISSING_FRACTION)
4665  {
4666  break;
4667  }
4668 
4669  if (*the_double < 0.0)
4670  {
4671  fraction_part = -fraction_part;
4672  }
4673  *the_double += fraction_part;
4674  type = cnv_fmt_lex (&token);
4675 
4676  /* WARNING: must handle scientific format here. */
4677  }
4678  }
4679 
4680  if (type != FT_NONE)
4681  {
4682  /* Invalid chars at the end. */
4683  error = cnv_bad_char (token.raw_text, !ffmt_valid_char (&token));
4684  break;
4685  }
4686 
4687  if (decimal_missing)
4688  {
4689  error = CNV_ERR_NO_DECIMAL;
4691  break;
4692  }
4693  }
4694  while (0);
4695  return error ? NULL : cnv_fmt_next_token ();
4696 }
4697 
4698 #if defined (ENABLE_UNUSED_FUNCTION)
4699 /*
4700  * ffmt_print() - Change the given string to a representation of the given
4701  * double value in the given format. if max_size is not long enough to
4702  * contain the new double string, then an error is returned.
4703  * return:
4704  * ffmt(in) :
4705  * the_double(in) :
4706  * string(out) :
4707  * max_size(in) : the maximum number of chars that can be stored in
4708  * the string (including final '\0' char)
4709  */
4710 static int
4711 ffmt_print (FLOAT_FORMAT * ffmt, double the_double, char *string, int max_size)
4712 {
4713  int error = 0;
4714  FMT_TOKEN token;
4715  FMT_TOKEN_TYPE type;
4716  double the_value;
4717  bool unlimited_fraction = ffmt->decimal && !ffmt->fractional_digits;
4718  int max_digits = (!ffmt->integral_digits
4719  || unlimited_fraction) ? FMT_MAX_DIGITS : ffmt->integral_digits + ffmt->fractional_digits;
4720  DB_C_INT nchars = (the_double < 0.0
4721  || ffmt->sign_required) + ffmt->decimal + max_digits + (unlimited_fraction ? FLT_DIG : 0) +
4722  (ffmt->scientific ? strlen (LOCAL_EXP_LENGTH) : 0);
4723  /* Create print format string. */
4724  const char *fmt_sign = ffmt->sign_required ? "+" : "";
4725  const char *fmt_zeroes = ffmt->integral_type != DIGIT_Z ? "0" : "";
4726  const char *fmt_type = ffmt->scientific ? "E" : "f";
4727  const char *fmt_precision = unlimited_fraction ? "*" : "*.*";
4728  const char *fmt = adj_ar_concat_strings ("%", fmt_sign, fmt_zeroes,
4729  fmt_precision, fmt_type, NULL);
4730  /* Print undecorated value string. */
4731  ADJ_ARRAY *buffer = cnv_get_string_buffer (nchars - max_digits + FMT_MAX_DIGITS);
4732  if (unlimited_fraction)
4733  {
4734  sprintf ((char *) adj_ar_get_buffer (buffer), fmt, nchars, the_double);
4735  }
4736  else
4737  {
4738  sprintf ((char *) adj_ar_get_buffer (buffer), fmt, nchars, (DB_C_INT) (ffmt->fractional_digits), the_double);
4739  }
4740 
4741  /* Trim leading blanks... */
4742  if (!ffmt->integral_digits || ffmt->integral_type == DIGIT_Z)
4743  {
4744  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
4745  while (cnv_fmt_lex (&token) == FT_UNKNOWN && mbs_eql (token.text, LOCAL_SPACE));
4746  adj_ar_remove (buffer, 0, (int) (cnv_fmt_next_token () - token.length - (char *) adj_ar_get_buffer (buffer)));
4747  }
4748 
4749  /* ...or replace with leading stars. */
4750  else if (ffmt->integral_type == DIGIT_STAR)
4751  {
4752  int start;
4753  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
4754  while ((type = cnv_fmt_lex (&token)) == FT_MINUS || type == FT_PLUS);
4755  start = (int) (cnv_fmt_next_token () - token.length - (const char *) adj_ar_get_buffer (buffer));
4756  if (type == FT_ZEROES)
4757  {
4758  int nzeroes;
4759  int sl = strlen (LOCAL_STAR);
4760  adj_ar_remove (buffer, start, start + token.length);
4761  for (nzeroes = intl_mbs_len (token.text); nzeroes > 0; nzeroes--)
4762  {
4763  adj_ar_insert (buffer, LOCAL_STAR, sl, start);
4764  }
4765  }
4766  }
4767 
4768  /* Replace trailing zeroes. */
4769  if (ffmt->decimal && ffmt->fractional_type != DIGIT_9)
4770  {
4771  int start;
4772  int length;
4773  int nzeroes;
4774  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
4775  while (cnv_fmt_lex (&token) != FT_DECIMAL);
4776  for (start = 0, nzeroes = 0, length = 0, type = cnv_fmt_lex (&token); type == FT_NUMBER || type == FT_ZEROES;
4777  type = cnv_fmt_lex (&token))
4778  {
4779  if (type == FT_ZEROES)
4780  {
4781  start = (int) (cnv_fmt_next_token () - token.length - (const char *) adj_ar_get_buffer (buffer));
4782  length = token.length;
4783  nzeroes = intl_mbs_len (token.text);
4784  }
4785  }
4786 
4787  if (nzeroes > 0)
4788  {
4789  adj_ar_remove (buffer, start, start + length);
4790  if (ffmt->fractional_type == DIGIT_STAR)
4791  {
4792  int sl = strlen (LOCAL_STAR);
4793  for (; nzeroes > 0; nzeroes--)
4794  {
4795  adj_ar_insert (buffer, LOCAL_STAR, sl, start);
4796  }
4797  }
4798  }
4799  }
4800 
4801  /* Add thousands separators. */
4802  if (ffmt->thousands)
4803  {
4804  fmt_add_thousands (buffer, NULL);
4805  }
4806 
4807  /* Too many digits? */
4808  if (!ffmt_value (ffmt, (const char *) adj_ar_get_buffer (buffer), &the_value))
4809  {
4810  error = co_code ();
4811  }
4812 
4813  /* Enough room to copy completed value string? */
4814  else if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
4815  {
4816  error = CNV_ERR_STRING_TOO_LONG;
4817  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
4818  }
4819 
4820  else
4821  {
4822  strcpy (string, (char *) adj_ar_get_buffer (buffer));
4823  }
4824 
4825  return error;
4826 }
4827 #endif
4828 
4829 /* Monetary Format Descriptor Functions */
4830 
4831 /*
4832  * mfmt_valid_char() - Return true if token chars can legally appear in
4833  * a monetary value string.
4834  * return:
4835  * token(in) :
4836  */
4837 static bool
4839 {
4840  FMT_TOKEN_TYPE type = token->type;
4841 
4842  return type == FT_CURRENCY || type == FT_NUMBER || type == FT_ZEROES || type == FT_MINUS || type == FT_STARS
4843  || type == FT_DECIMAL || type == FT_THOUSANDS || mbs_eql (token->text, local_thousands ());
4844 }
4845 
4846 /*
4847  * mfmt_new() - Initialize a descriptor for the given monetary format string.
4848  * return: void
4849  * mfmt(out) :
4850  * format(in) :
4851  * currency_type(in) :
4852  */
4853 static void
4854 mfmt_new (MONETARY_FORMAT * mfmt, const char *format, DB_CURRENCY currency_type)
4855 {
4856  wchar_t idc[3];
4857  const wchar_t *wfmt = cnv_wcs (format);
4858  const wchar_t *fraction_part = wcsstr (wfmt, FMT_DECIMAL ());
4859  const wchar_t *currency_part = wcsstr (wfmt, FMT_CURRENCY ());
4860  const wchar_t *integer_part;
4861 
4862  mfmt->currency = currency_type;
4863  mfmt->mode = cnv_fmt_number_mode (cnv_currency_zone (currency_type));
4864 
4865  if (wcs_eql (wfmt, FMT_CURRENCY ()) || !wcslen (wfmt))
4866  {
4867  mfmt->format = CURRENCY_FIRST;
4868  }
4869  else if (currency_part == NULL)
4870  {
4871  mfmt->format = CURRENCY_NONE;
4872  }
4873  else if (currency_part == wfmt)
4874  {
4875  mfmt->format = CURRENCY_FIRST;
4876  }
4877  else
4878  {
4879  mfmt->format = CURRENCY_LAST;
4880  }
4881 
4882  mfmt->thousands = wcsstr (wfmt, FMT_THOUSANDS ()) != NULL;
4883 
4884  if (mfmt->format == CURRENCY_FIRST && wcslen (wfmt) && currency_part != NULL)
4885  {
4886  integer_part = currency_part + 1;
4887  }
4888  else
4889  {
4890  integer_part = wfmt;
4891  }
4892 
4893  if (fraction_part)
4894  {
4895  fraction_part++;
4896  }
4897 
4898  mfmt->decimal = (fraction_part != NULL || !wcslen (integer_part));
4899  mfmt->fractional_type = DIGIT_Z;
4900 
4901  if (fraction_part)
4902  {
4903  mfmt->fractional_digits = wcsspn (fraction_part, FMT_Z ());
4904  }
4905  else if (mfmt->decimal)
4906  {
4907  mfmt->fractional_type = DIGIT_9;
4908  mfmt->fractional_digits = 2;
4909  }
4910  else
4911  {
4912  mfmt->fractional_digits = 0;
4913  }
4914 
4915  if (fraction_part && !mfmt->fractional_digits)
4916  {
4917  mfmt->fractional_digits = wcsspn (fraction_part, FMT_9 ());
4918  if (mfmt->fractional_digits)
4919  {
4920  mfmt->fractional_type = DIGIT_9;
4921  }
4922  else
4923  {
4924  mfmt->fractional_digits = wcsspn (fraction_part, FMT_STAR ());
4925  if (mfmt->fractional_digits)
4926  {
4927  mfmt->fractional_type = DIGIT_STAR;
4928  }
4929  else
4930  {
4931  mfmt->fractional_type = DIGIT_Z;
4932  }
4933  }
4934  }
4935 
4936  mfmt->integral_type = DIGIT_Z;
4937 
4938  mfmt->integral_digits = wcsspn (integer_part, WCSCAT (idc, FMT_Z (), FMT_THOUSANDS ())) - mfmt->thousands;
4939 
4940  if (mfmt->integral_digits <= 0)
4941  {
4942  mfmt->integral_digits = wcsspn (integer_part, WCSCAT (idc, FMT_9 (), FMT_THOUSANDS ())) - mfmt->thousands;
4943 
4944  if (mfmt->integral_digits > 0)
4945  {
4946  mfmt->integral_type = DIGIT_9;
4947  }
4948  else
4949  {
4950  mfmt->integral_digits = wcsspn (integer_part, WCSCAT (idc, FMT_STAR (), FMT_THOUSANDS ())) - mfmt->thousands;
4951  if (mfmt->integral_digits > 0)
4952  {
4953  mfmt->integral_type = DIGIT_STAR;
4954  }
4955  else
4956  {
4957  mfmt->integral_type = DIGIT_Z;
4958  }
4959  }
4960  }
4961 }
4962 
4963 /*
4964  * mfmt_value() - Get the double value represented by the value string.
4965  * Return a pointer to the first char of the string after the last value
4966  * char. If an error occurs, then the value is unchanged and NULL is
4967  * returned.
4968  * return:
4969  * mfmt(in) :
4970  * string(in) :
4971  * the_double(out) :
4972  */
4973 static const char *
4974 mfmt_value (MONETARY_FORMAT * mfmt, const char *string, double *the_double)
4975 {
4976  int error = 0;
4977  FMT_TOKEN token;
4978  FMT_TOKEN_TYPE type;
4979  bool decimal_missing = false;
4980 
4981  cnv_fmt_analyze (string, mfmt->mode);
4982 
4983  do
4984  {
4985  if (mfmt->format == CURRENCY_FIRST && cnv_fmt_lex (&token) != FT_CURRENCY)
4986  {
4987  error = CNV_ERR_NO_CURRENCY;
4989  break;
4990  }
4991 
4992  /* Get value of integer part. */
4993  error = fmt_integral_value (mfmt->integral_type, mfmt->integral_digits, false, mfmt->thousands, the_double);
4994 
4995  if (error && error != CNV_ERR_MISSING_INTEGER)
4996  {
4997  break;
4998  }
4999 
5000  type = cnv_fmt_lex (&token);
5001 
5002  if (mfmt->decimal)
5003  {
5004  /* Decimal point found? */
5005  decimal_missing = (type != FT_DECIMAL);
5006  if (!decimal_missing)
5007  {
5008  double fraction_part;
5009 
5010  if (error)
5011  {
5012  break; /* integer digit really missing. */
5013  }
5014 
5015  /* get value of fraction part. */
5016  error = fmt_fractional_value (mfmt->fractional_type, mfmt->fractional_digits, &fraction_part);
5017 
5018  if (error && error != CNV_ERR_MISSING_FRACTION)
5019  {
5020  break;
5021  }
5022 
5023  if (*the_double < 0.0)
5024  {
5025  fraction_part = -fraction_part;
5026  }
5027  *the_double += fraction_part;
5028  type = cnv_fmt_lex (&token);
5029  }
5030  }
5031 
5032  if (mfmt->format == CURRENCY_LAST)
5033  {
5034  if (type == FT_NONE)
5035  {
5036  error = CNV_ERR_NO_CURRENCY;
5038  break;
5039  }
5040  if (type == FT_CURRENCY)
5041  {
5042  type = cnv_fmt_lex (&token);
5043  }
5044  }
5045 
5046  if (type != FT_NONE)
5047  {
5048  /* Invalid chars at the end. */
5049  error = cnv_bad_char (token.raw_text, !mfmt_valid_char (&token));
5050  break;
5051  }
5052 
5053  if (decimal_missing)
5054  {
5055  error = CNV_ERR_NO_DECIMAL;
5057  break;
5058  }
5059  }
5060  while (0);
5061 
5062  return error ? NULL : cnv_fmt_next_token ();
5063 }
5064 
5065 #if defined (ENABLE_UNUSED_FUNCTION)
5066 /*
5067  * mfmt_print() - Change the given string to a representation of the given
5068  * double value in the given format. if the max_size is not long enough to
5069  * contain the new double string, then an error is returned.
5070  * return:
5071  * mfmt(in) :
5072  * the_double(in) :
5073  * string(out) :
5074  * max_size(in) :the maximum number of chars that can be stored in
5075  * the string (including final '\0' char);
5076  */
5077 static int
5078 mfmt_print (MONETARY_FORMAT * mfmt, double the_double, char *string, int max_size)
5079 {
5080  int error = 0;
5081  FMT_TOKEN token;
5082  FMT_TOKEN_TYPE type;
5083  double the_value;
5084 
5085  bool unlimited_fraction = mfmt->decimal && !mfmt->fractional_digits;
5086 
5087  int max_digits = (!mfmt->integral_digits
5088  || unlimited_fraction) ? FMT_MAX_DIGITS : mfmt->integral_digits + mfmt->fractional_digits;
5089  DB_C_INT nchars = (the_double < 0.0) + mfmt->decimal + max_digits;
5090 
5091  /* Create print format string. */
5092  const char *fmt_sign = "";
5093  const char *fmt_zeroes = mfmt->integral_type != DIGIT_Z ? "0" : "";
5094  const char *fmt_type = "f";
5095  const char *fmt_precision = unlimited_fraction ? "*" : "*.*";
5096 
5097  const char *fmt = adj_ar_concat_strings ("%", fmt_sign, fmt_zeroes,
5098  fmt_precision, fmt_type, NULL);
5099  /* Print undecorated value string. */
5100  ADJ_ARRAY *buffer = cnv_get_string_buffer (nchars - max_digits + FMT_MAX_DIGITS);
5101  if (unlimited_fraction)
5102  {
5103  sprintf ((char *) adj_ar_get_buffer (buffer), fmt, nchars, the_double);
5104  }
5105  else
5106  {
5107  sprintf ((char *) adj_ar_get_buffer (buffer), fmt, nchars, (DB_C_INT) (mfmt->fractional_digits), the_double);
5108  }
5109 
5110  /* Trim leading blanks... */
5111  if (!mfmt->integral_digits || mfmt->integral_type == DIGIT_Z)
5112  {
5113  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
5114  while (cnv_fmt_lex (&token) == FT_UNKNOWN && mbs_eql (token.text, LOCAL_SPACE));
5115  adj_ar_remove (buffer, 0,
5116  CAST_STRLEN (cnv_fmt_next_token () - token.length - (char *) adj_ar_get_buffer (buffer)));
5117  }
5118 
5119  /* ...or replace with leading stars. */
5120  else if (mfmt->integral_type == DIGIT_STAR)
5121  {
5122  int start;
5123 
5124  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
5125  while ((type = cnv_fmt_lex (&token)) == FT_MINUS || type == FT_PLUS);
5126  start = CAST_STRLEN (cnv_fmt_next_token () - token.length - (const char *) adj_ar_get_buffer (buffer));
5127 
5128  if (type == FT_ZEROES)
5129  {
5130  int nzeroes;
5131  int sl = strlen (LOCAL_STAR);
5132  adj_ar_remove (buffer, start, start + token.length);
5133  for (nzeroes = intl_mbs_len (token.text); nzeroes > 0; nzeroes--)
5134  {
5135  adj_ar_insert (buffer, LOCAL_STAR, sl, start);
5136  }
5137  }
5138  }
5139 
5140  /* Replace trailing zeroes. */
5141  if (mfmt->decimal && mfmt->fractional_type != DIGIT_9)
5142  {
5143  int start;
5144  int length;
5145  int nzeroes;
5146 
5147  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
5148  while (cnv_fmt_lex (&token) != FT_DECIMAL);
5149 
5150  for (start = 0, length = 0, nzeroes = 0, type = cnv_fmt_lex (&token); type == FT_NUMBER || type == FT_ZEROES;
5151  type = cnv_fmt_lex (&token))
5152  {
5153  if (type == FT_ZEROES)
5154  {
5155  start = CAST_STRLEN (cnv_fmt_next_token () - token.length - (const char *) adj_ar_get_buffer (buffer));
5156  length = token.length;
5157  nzeroes = intl_mbs_len (token.text);
5158  }
5159  }
5160  if (nzeroes > 0)
5161  {
5162  adj_ar_remove (buffer, start, start + length);
5163  if (mfmt->fractional_type == DIGIT_STAR)
5164  {
5165  int sl = strlen (LOCAL_STAR);
5166  for (; nzeroes > 0; nzeroes--)
5167  {
5168  adj_ar_insert (buffer, LOCAL_STAR, sl, start);
5169  }
5170  }
5171  }
5172  }
5173 
5174  /* Add thousands separators. */
5175  if (mfmt->thousands)
5176  {
5177  fmt_add_thousands (buffer, NULL);
5178  }
5179 
5180  fmt_add_currency (buffer, NULL, mfmt);
5181 
5182  /* Too many digits? */
5183  if (!mfmt_value (mfmt, (const char *) adj_ar_get_buffer (buffer), &the_value))
5184  {
5185  error = co_code ();
5186  }
5187 
5188  /* Enough room to copy completed value string? */
5189  else if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
5190  {
5191  error = CNV_ERR_STRING_TOO_LONG;
5192  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
5193  }
5194 
5195  else
5196  {
5197  strcpy (string, (char *) adj_ar_get_buffer (buffer));
5198  }
5199 
5200  return error;
5201 }
5202 #endif
5203 
5204 /* Integer Format Descriptor Functions */
5205 
5206 /*
5207  * ifmt_valid_char() - Return true if token chars can legally appear in
5208  * an integer value string.
5209  * return:
5210  * token(in) :
5211  */
5212 static bool
5214 {
5215  FMT_TOKEN_TYPE type = token->type;
5216 
5217  return type == FT_NUMBER || type == FT_ZEROES || type == FT_MINUS || type == FT_PLUS || type == FT_STARS
5218  || type == FT_THOUSANDS || mbs_eql (token->text, local_thousands ());
5219 }
5220 
5221 /*
5222  * ifmt_new() - Initialize a descriptor for the given integer format string.
5223  * return:
5224  * ifmt(in) :
5225  * format(in) :
5226  */
5227 static void
5228 ifmt_new (INTEGER_FORMAT * ifmt, const char *format)
5229 {
5230  wchar_t idc[3];
5231  const wchar_t *wfmt = cnv_wcs (format);
5232  const wchar_t *x_part;
5233 
5234  x_part = wcsstr (wfmt, FMT_X ());
5235  if (!x_part)
5236  {
5237  /* Numeric format */
5238  const wchar_t *integer_part = wcsstr (wfmt, FMT_PLUS ());
5239  integer_part = integer_part ? integer_part + 1 : wfmt;
5240 
5241  ifmt->sign_required = integer_part != wfmt;
5242  ifmt->thousands = wcsstr (wfmt, FMT_THOUSANDS ()) != NULL;
5243  ifmt->pattern = NULL;
5244 
5245  ifmt->integral_type = DIGIT_Z;
5246  if (!
5247  ((ifmt->integral_digits =
5248  wcsspn (integer_part, WCSCAT (idc, FMT_Z (), FMT_THOUSANDS ())) - ifmt->thousands) > 0))
5249  {
5250 
5251  ifmt->integral_type =
5252  ((ifmt->integral_digits =
5253  wcsspn (integer_part,
5254  WCSCAT (idc, FMT_9 (),
5255  FMT_THOUSANDS ())) - ifmt->thousands) > 0) ? DIGIT_9 : ((ifmt->integral_digits =
5256  wcsspn (integer_part,
5257  WCSCAT (idc, FMT_STAR (),
5259  ())) -
5260  ifmt->thousands) >
5261  0) ? DIGIT_STAR : DIGIT_Z;
5262  }
5263  }
5264 #if defined (ENABLE_UNUSED_FUNCTION)
5265  else
5266  {
5267  /* Text pattern format. */
5268  FMT_TOKEN_TYPE ttype;
5269  FMT_TOKEN token;
5270 
5271  ifmt->sign_required = false;
5272  ifmt->thousands = false;
5273  ifmt->integral_digits = 0;
5274  ifmt->integral_type = DIGIT_9;
5275  ifmt->pattern = format;
5276 
5277  /* Count max digits allowed. */
5279  while ((ttype = cnv_fmt_lex (&token)) != FT_NONE)
5280  {
5281  if (ttype == FT_NUMBER)
5282  {
5283  ifmt->integral_digits += intl_mbs_len (token.text);
5284  }
5285  }
5286  }
5287 #endif
5288 }
5289 
5290 /*
5291  * ifmt_value() - Get the integer value represented by the value string.
5292  * Return a pointer to the first char of the string after the last value
5293  * char. If an error occurs, then the value is unchanged and NULL is
5294  * returned.
5295  * return:
5296  * ifmt(in) :
5297  * string(in) :
5298  * the_integer(out) :
5299  */
5300 static const char *
5301 ifmt_value (INTEGER_FORMAT * ifmt, const char *string, int *the_integer)
5302 {
5303  return
5304 #if defined (ENABLE_UNUSED_FUNCTION)
5305  ifmt->pattern ? ifmt_text_value (ifmt, string, the_integer) :
5306 #endif
5307  ifmt_numeric_value (ifmt, string, the_integer);
5308 }
5309 
5310 /*
5311  * bifmt_value() - Get the big integer value represented by the value string.
5312  * Return a pointer to the first char of the string after the last value
5313  * char. If an error occurs, then the value is unchanged and NULL is
5314  * returned.
5315  * return:
5316  * bifmt(in) :
5317  * string(in) :
5318  * the_bigint(out) :
5319  */
5320 static const char *
5321 bifmt_value (INTEGER_FORMAT * ifmt, const char *string, DB_BIGINT * the_bigint)
5322 {
5323  return
5324 #if defined (ENABLE_UNUSED_FUNCTION)
5325  ifmt->pattern ? bifmt_text_value (ifmt, string, the_bigint) :
5326 #endif
5327  bifmt_numeric_value (ifmt, string, the_bigint);
5328 }
5329 
5330 /*
5331  * ifmt_numeric_value() - Get the integer value represented by the value
5332  * string, using the given numeric format. Return a pointer to the first
5333  * char of the string after the last value char. If an error occurs, then
5334  * the value is unchanged and NULL is returned.
5335  * return:
5336  * ifmt(in) :
5337  * string(in) :
5338  * the_integer(out) :
5339  */
5340 static const char *
5341 ifmt_numeric_value (INTEGER_FORMAT * ifmt, const char *string, int *the_integer)
5342 {
5343  int error = 0;
5344  FMT_TOKEN token;
5345  double the_double;
5346 
5347  cnv_fmt_analyze (string, FL_LOCAL_NUMBER);
5348 
5349  do
5350  {
5351  /* Get value of integer part. */
5352  error =
5354  &the_double);
5355 
5356  if ((!error || error == CNV_ERR_MISSING_INTEGER) && cnv_fmt_lex (&token) != FT_NONE)
5357  {
5358  /* Invalid chars at the end. */
5359  error = cnv_bad_char (token.raw_text, !ifmt_valid_char (&token));
5360  }
5361  if (error)
5362  {
5363  break;
5364  }
5365 
5366  if (the_double > DB_INT32_MAX)
5367  {
5368  error = CNV_ERR_INTEGER_OVERFLOW;
5370  break;
5371  }
5372  if (the_double < DB_INT32_MIN)
5373  {
5374  error = CNV_ERR_INTEGER_UNDERFLOW;
5376  break;
5377  }
5378  *the_integer = (int) the_double;
5379  }
5380  while (0);
5381 
5382  return error ? NULL : cnv_fmt_next_token ();
5383 }
5384 
5385 /*
5386  * bifmt_numeric_value() - Get the integer value represented by the value
5387  * string, using the given numeric format. Return a pointer to the first
5388  * char of the string after the last value char. If an error occurs, then
5389  * the value is unchanged and NULL is returned.
5390  * return:
5391  * ifmt(in) :
5392  * string(in) :
5393  * the_integer(out) :
5394  */
5395 static const char *
5396 bifmt_numeric_value (INTEGER_FORMAT * ifmt, const char *string, DB_BIGINT * the_bigint)
5397 {
5398  int error = 0;
5399  FMT_TOKEN token;
5400  double the_double;
5401 
5402  cnv_fmt_analyze (string, FL_LOCAL_NUMBER);
5403 
5404  do
5405  {
5406  /* Get value of integer part. */
5407  error =
5409  &the_double);
5410 
5411  if ((!error || error == CNV_ERR_MISSING_INTEGER) && cnv_fmt_lex (&token) != FT_NONE)
5412  {
5413  /* Invalid chars at the end. */
5414  error = cnv_bad_char (token.raw_text, !ifmt_valid_char (&token));
5415  }
5416  if (error)
5417  {
5418  break;
5419  }
5420 
5421  if (the_double > DB_BIGINT_MAX)
5422  {
5423  error = CNV_ERR_INTEGER_OVERFLOW;
5425  break;
5426  }
5427  if (the_double < DB_BIGINT_MIN)
5428  {
5429  error = CNV_ERR_INTEGER_UNDERFLOW;
5431  break;
5432  }
5433  *the_bigint = (DB_BIGINT) the_double;
5434  }
5435  while (0);
5436 
5437  return error ? NULL : cnv_fmt_next_token ();
5438 }
5439 
5440 #if defined (ENABLE_UNUSED_FUNCTION)
5441 /*
5442  * ifmt_text_value() - Get the integer value represented by the value string,
5443  * using the given text format. Return a pointer to the first char of the
5444  * string after the last value char. If an error occurs, then the value
5445  * is unchanged and NULL is returned.
5446  * return:
5447  * ifmt(in) :
5448  * string(in) :
5449  * the_integer(out) :
5450  */
5451 static const char *
5452 ifmt_text_value (INTEGER_FORMAT * ifmt, const char *string, int *the_integer)
5453 {
5454  ADJ_ARRAY *vstring = cnv_get_value_string_buffer (0);
5455  int nchars;
5456 
5457  adj_ar_replace (vstring, string, strlen (string) + 1, 0, ADJ_AR_EOA);
5458  nchars = ifmt_text_numeric (ifmt, vstring);
5459 
5460  return (!nchars
5461  || !ifmt_numeric_value (ifmt, (const char *) adj_ar_get_buffer (vstring),
5462  the_integer)) ? NULL : string + nchars;
5463 }
5464 
5465 /*
5466  * ifmt_text_value() - Get the integer value represented by the value string,
5467  * using the given text format. Return a pointer to the first char of the
5468  * string after the last value char. If an error occurs, then the value
5469  * is unchanged and NULL is returned.
5470  * return:
5471  * ifmt(in) :
5472  * string(in) :
5473  * the_integer(out) :
5474  */
5475 static const char *
5476 bifmt_text_value (INTEGER_FORMAT * ifmt, const char *string, DB_BIGINT * the_bigint)
5477 {
5478  ADJ_ARRAY *vstring = cnv_get_value_string_buffer (0);
5479  int nchars;
5480 
5481  adj_ar_replace (vstring, string, strlen (string) + 1, 0, ADJ_AR_EOA);
5482  nchars = ifmt_text_numeric (ifmt, vstring);
5483 
5484  return (!nchars
5485  || !bifmt_numeric_value (ifmt, (const char *) adj_ar_get_buffer (vstring),
5486  the_bigint)) ? NULL : string + nchars;
5487 }
5488 
5489 /*
5490  * ifmt_text_numeric() - Convert a text format integer string into a numeric
5491  * format string. If an error occurs, return 0; otherwise, return the number
5492  * of text string bytes processed.
5493  * return:
5494  * ifmt(in) :
5495  * text_string(out) :
5496  */
5497 static int
5498 ifmt_text_numeric (INTEGER_FORMAT * ifmt, ADJ_ARRAY * text_string)
5499 {
5500  int error = 0;
5501  int nbytes = 0;
5502  FMT_TOKEN token;
5503  FMT_TOKEN_TYPE ttype;
5504  const char *ts = (const char *) adj_ar_get_buffer (text_string);
5505  const char *sp;
5506  int sbytes = 0;
5507 
5508  /* Strip pattern chars from numeric value string according to format. */
5509  for (sp = ts, cnv_fmt_analyze (ifmt->pattern, FL_INTEGER_FORMAT); !error && (ttype = cnv_fmt_lex (&token)) != FT_NONE;
5510  nbytes += sbytes)
5511  {
5512 
5513  if (ttype == FT_PATTERN)
5514  {
5515  if (strncmp (sp, token.text, token.length))
5516  {
5517  error = CNV_ERR_BAD_PATTERN;
5518  co_signal (error, CNV_ER_FMT_BAD_PATTERN, token.text, sp - ts);
5519  }
5520  else
5521  {
5522  /* Remove pattern chars. */
5523  int i = CAST_STRLEN (sp - ts);
5524  adj_ar_remove (text_string, i, i + token.length);
5525  sbytes = token.length;
5526  }
5527  }
5528  else
5529  {
5530  sbytes = intl_mbs_spn (sp, FMT_DIGITS ());
5531  sp += sbytes;
5532  }
5533  }
5534 
5535  /* All value string chars matched? */
5536  if (!error && strlen (sp))
5537  {
5538  error = cnv_bad_char (sp, true);
5539  }
5540 
5541  return error ? 0 : nbytes;
5542 }
5543 
5544 /*
5545  * ifmt_print() - Change the given string to a representation of the given
5546  * integer value in the given format. If max_size is not long enough to
5547  * contain the new int string, then an error is returned.
5548  * return:
5549  * ifmt(in) :
5550  * the_integer(in) :
5551  * string(out) :
5552  * max_size(in) : the maximum number of chars that can be stored in
5553  * the string (including final '\0' char);
5554  */
5555 static int
5556 ifmt_print (INTEGER_FORMAT * ifmt, DB_BIGINT the_bigint, char *string, int max_size)
5557 {
5558  return ifmt->pattern ? ifmt_text_print (ifmt, the_bigint, string, max_size) : ifmt_numeric_print (ifmt, the_bigint,
5559  string, max_size);
5560 }
5561 
5562 /*
5563  * ifmt_numeric_print() - Change the given string to a representation of
5564  * the given integer value in the given numeric format. if max_size is not
5565  * long enough to contain the new int string, then an error is returned.
5566  * return:
5567  * ifmt(in) :
5568  * the_integer(in) :
5569  * string(out) :
5570  * max_size(in) : the maximum number of chars that can be stored in
5571  * the string (including final '\0' char)
5572  */
5573 static int
5574 ifmt_numeric_print (INTEGER_FORMAT * ifmt, DB_BIGINT the_bigint, char *string, int max_size)
5575 {
5576  int error = 0;
5577  int the_value;
5578  FMT_TOKEN token;
5579  FMT_TOKEN_TYPE type;
5580 
5581  int max_digits = !ifmt->integral_digits ? FMT_MAX_DIGITS : ifmt->integral_digits;
5582 
5583  DB_C_INT nchars = (the_bigint < 0.0 || ifmt->sign_required) + max_digits;
5584 
5585  /* Create print format string. */
5586  const char *fmt_sign = ifmt->sign_required ? "+" : "";
5587  const char *fmt_zeroes = ifmt->integral_type != DIGIT_Z ? "0" : "";
5588  const char *fmt_width = "*";
5589 
5590  const char *fmt = adj_ar_concat_strings ("%", fmt_sign, fmt_zeroes, fmt_width, "d", NULL);
5591 
5592  /* Print undecorated value string. */
5593  ADJ_ARRAY *buffer = cnv_get_string_buffer (nchars - max_digits + FMT_MAX_DIGITS);
5594  sprintf ((char *) adj_ar_get_buffer (buffer), fmt, nchars, the_bigint);
5595 
5596  /* Trim leading blanks... */
5597  if (!ifmt->integral_digits || ifmt->integral_type == DIGIT_Z)
5598  {
5599  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
5600  while (cnv_fmt_lex (&token) == FT_UNKNOWN && mbs_eql (token.text, LOCAL_SPACE));
5601  adj_ar_remove (buffer, 0,
5602  CAST_STRLEN (cnv_fmt_next_token () - token.length - (char *) adj_ar_get_buffer (buffer)));
5603  }
5604 
5605  /* ...or replace with leading stars. */
5606  else if (ifmt->integral_type == DIGIT_STAR)
5607  {
5608  int start;
5609 
5610  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
5611  while ((type = cnv_fmt_lex (&token)) == FT_MINUS || type == FT_PLUS);
5612  start = CAST_STRLEN (cnv_fmt_next_token () - token.length - (const char *) adj_ar_get_buffer (buffer));
5613  if (type == FT_ZEROES)
5614  {
5615  int nzeroes;
5616  int sl = strlen (LOCAL_STAR);
5617  adj_ar_remove (buffer, start, start + token.length);
5618  for (nzeroes = intl_mbs_len (token.text); nzeroes > 0; nzeroes--)
5619  {
5620  adj_ar_insert (buffer, LOCAL_STAR, sl, start);
5621  }
5622  }
5623  }
5624 
5625  /* Add thousands separators. */
5626  if (ifmt->thousands)
5627  {
5628  fmt_add_thousands (buffer, NULL);
5629  }
5630 
5631  /* Too many digits? */
5632  if (!ifmt_numeric_value (ifmt, (const char *) adj_ar_get_buffer (buffer), &the_value))
5633  {
5634  error = co_code ();
5635  }
5636 
5637  /* Enough room to copy completed value string? */
5638  else if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
5639  {
5640  error = CNV_ERR_STRING_TOO_LONG;
5641  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
5642  }
5643 
5644  else
5645  {
5646  strcpy (string, (char *) adj_ar_get_buffer (buffer));
5647  }
5648 
5649  return error;
5650 }
5651 
5652 /*
5653  * ifmt_text_print() - Change the given string to a representation of
5654  * the given integer value in the given text format. if max_size is not
5655  * long enough to contain the new int string, then an error is returned.
5656  * return:
5657  * ifmt(in) :
5658  * the_integer(in) :
5659  * string(out) :
5660  * max_size(in) : the maximum number of chars that can be stored in
5661  * the string (including final '\0' char)
5662  */
5663 static int
5664 ifmt_text_print (INTEGER_FORMAT * ifmt, DB_BIGINT the_bigint, char *string, int max_size)
5665 {
5666  ADJ_ARRAY *vstring = cnv_get_value_string_buffer (strlen (ifmt->pattern));
5667 
5668  /* Get numeric value string. */
5669  int error = ifmt_numeric_print (ifmt, the_bigint,
5670  (char *) adj_ar_get_buffer (vstring),
5671  strlen (ifmt->pattern) + 1);
5672 
5673  if (!error)
5674  {
5675  /* Elaborate text value string according to format pattern. */
5676  ifmt_numeric_text (ifmt, vstring);
5677 
5678  /* Enough room to copy completed value string? */
5679  if ((int) strlen ((char *) adj_ar_get_buffer (vstring)) >= max_size)
5680  {
5681  error = CNV_ERR_STRING_TOO_LONG;
5682  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
5683  }
5684 
5685  else
5686  {
5687  strcpy (string, (char *) adj_ar_get_buffer (vstring));
5688  }
5689  }
5690 
5691  return error;
5692 }
5693 
5694 /*
5695  * ifmt_numeric_text() - Convert the numeric string into a text format integer
5696  * string according to the given text format.
5697  * return:
5698  * ifmt(in) :
5699  * numeric_string(in/out) :
5700  */
5701 static void
5702 ifmt_numeric_text (INTEGER_FORMAT * ifmt, ADJ_ARRAY * numeric_string)
5703 {
5704  FMT_TOKEN token;
5705  FMT_TOKEN_TYPE ttype;
5706  int i;
5707 
5708  /* Elaborate text value string according to format pattern. */
5709  for (i = 0, cnv_fmt_analyze (ifmt->pattern, FL_INTEGER_FORMAT); (ttype = cnv_fmt_lex (&token)) != FT_NONE;
5710  i += token.length)
5711  {
5712 
5713  if (ttype == FT_PATTERN)
5714  {
5715  adj_ar_insert (numeric_string, token.text, token.length, i);
5716  }
5717  }
5718 }
5719 #endif
5720 
5721 /* Bit String Format Descriptor Functions */
5722 
5723 /*
5724  * bfmt_valid_char() - Return true if token chars can legally appear in
5725  * a bit string.
5726  * return:
5727  * token(in) :
5728  */
5729 static bool
5731 {
5732  FMT_TOKEN_TYPE type = token->type;
5733  return (type == FT_BINARY_DIGITS || type == FT_HEX_DIGITS);
5734 }
5735 
5736 /*
5737  * bfmt_new() - Initialize a descriptor for the given bit string
5738  * format string.
5739  * return:
5740  * bfmt(in) :
5741  * format(in) :
5742  */
5743 static void
5744 bfmt_new (BIT_STRING_FORMAT * bfmt, const char *format)
5745 {
5746  /* Text pattern format. */
5747  FMT_TOKEN_TYPE ttype;
5748  FMT_TOKEN token;
5749 
5751  if ((ttype = cnv_fmt_lex (&token)) == FT_HEX_DIGITS)
5752  {
5753  *bfmt = BIT_STRING_HEX;
5754  }
5755  else
5756  {
5757  *bfmt = BIT_STRING_BINARY;
5758  }
5759 }
5760 
5761 /*
5762  * bin_string_to_int() - Take a string made up of 8 or less '0' or '1'
5763  * characters and interprets them as an 8-bit integer. <nbits> describes
5764  * the number of characters that are to be extracted from <src>. If the
5765  * number of characters less than 8, the characters are assumed to be the
5766  * MSB of the result.
5767  * return:
5768  * src(in) :
5769  * nbits(in) :
5770  */
5771 static int
5772 bin_string_to_int (const char *src, int nbits)
5773 {
5774  int val;
5775  char my_bin[BITS_IN_BYTE + 1];
5776 
5777  strncpy (my_bin, src, BITS_IN_BYTE);
5778  my_bin[BITS_IN_BYTE] = '\0';
5779 
5780  parse_int (&val, my_bin, 2);
5781 
5782  return (val << (BITS_IN_BYTE - nbits));
5783 }
5784 
5785 /*
5786  * hex_string_to_int() - Take a string made up of 1 or 2 hexadecimal characters
5787  * and interprets them as an 8-bit integer. <nhex> describes the number
5788  * of characters that are to be extracted from <src>. If <src> has only one
5789  * character, it is assumed to be in the MSB of the result.
5790  * return:
5791  * src(in) :
5792  * nhex(in) :
5793  */
5794 static int
5795 hex_string_to_int (const char *src, int nhex)
5796 {
5797  int val;
5798  char my_hex[HEX_IN_BYTE + 1];
5799 
5800  strncpy (my_hex, src, HEX_IN_BYTE);
5801  my_hex[HEX_IN_BYTE] = '\0';
5802 
5803  parse_int (&val, my_hex, 16);
5804 
5805  return (val << ((HEX_IN_BYTE - nhex) * BITS_IN_HEX));
5806 }
5807 
5808 /*
5809  * bfmt_value() - Get the bit string value represented by the value string,
5810  * using the given bit string format. Return a pointer to the first char
5811  * of the string after the last value char. If an error occurs, then the
5812  * value is unchanged and NULL is returned.
5813  * return:
5814  * bfmt(in) :
5815  * string(in) :
5816  * the_db_bit(out) :
5817  */
5818 static const char *
5819 bfmt_value (BIT_STRING_FORMAT bfmt, const char *string, DB_VALUE * the_db_bit)
5820 {
5821  int error = 0;
5822  FMT_TOKEN token;
5823  FMT_TOKEN_TYPE ttype;
5824  char *the_bit_string = NULL;
5825  int length = 0;
5826  int byte_index = 0;
5827  const char *end;
5828  const char *src;
5829  int ndigs;
5830 
5831  /* Check for special case - Empty string is not the same as NULL */
5832  if (string[0] == '\0')
5833  {
5834  the_bit_string = (char *) db_private_alloc (NULL, 1);
5835  if (the_bit_string == NULL)
5836  {
5837  return NULL;
5838  }
5839  db_make_bit (the_db_bit, TP_FLOATING_PRECISION_VALUE, the_bit_string, 0);
5840  the_db_bit->need_clear = true;
5841  return cnv_fmt_next_token ();
5842  }
5843 
5844  cnv_fmt_analyze (string, FL_BIT_STRING);
5845 
5846  do
5847  {
5848  ttype = cnv_fmt_lex (&token);
5849 
5850  /* Process legal character according to the format */
5851  if (bfmt_valid_char (&token))
5852  {
5853  if (bfmt == BIT_STRING_BINARY)
5854  {
5855  if (ttype != FT_BINARY_DIGITS)
5856  {
5857  error = CNV_ERR_BAD_BINARY_DIGIT;
5858  break;
5859  }
5860  else
5861  {
5862  length += token.length;
5863  the_bit_string = (char *) db_private_alloc (NULL, BYTE_COUNT (length));
5864  if (!the_bit_string)
5865  {
5866  return NULL;
5867  }
5868  end = token.text + token.length;
5869  for (src = token.text; src < end; src += BITS_IN_BYTE)
5870  {
5871  ndigs = GET_MIN (BITS_IN_BYTE, CAST_STRLEN (end - src));
5872  the_bit_string[byte_index] = bin_string_to_int (src, ndigs);
5873  byte_index++;
5874  }
5875  }
5876  }
5877  else if (bfmt == BIT_STRING_HEX)
5878  {
5879  length = length + (token.length * BITS_IN_HEX);
5880  the_bit_string = (char *) db_private_alloc (NULL, BYTE_COUNT (length));
5881  if (!the_bit_string)
5882  {
5883  return NULL;
5884  }
5885  end = token.text + token.length;
5886  for (src = token.text; src < end; src += HEX_IN_BYTE)
5887  {
5888  ndigs = GET_MIN (HEX_IN_BYTE, CAST_STRLEN (end - src));
5889  the_bit_string[byte_index] = hex_string_to_int (src, ndigs);
5890  byte_index++;
5891  }
5892  }
5893  }
5894  /* End of string detected */
5895  else if (cnv_fmt_lex (&token) == FT_NONE)
5896  {
5897  break;
5898  }
5899  /* Illegal character detected */
5900  else
5901  {
5902  if (bfmt == BIT_STRING_BINARY)
5903  {
5904  error = CNV_ERR_BAD_BINARY_DIGIT;
5905  }
5906  else
5907  {
5908  error = CNV_ERR_BAD_HEX_DIGIT;
5909  }
5910  break;
5911  }
5912  }
5913  while (0);
5914 
5915  if (error)
5916  {
5917  if (the_bit_string)
5918  {
5919  db_private_free_and_init (NULL, the_bit_string);
5920  }
5921  return NULL;
5922  }
5923  else
5924  {
5925  db_make_bit (the_db_bit, length, the_bit_string, length);
5926  the_db_bit->need_clear = true;
5927  return cnv_fmt_next_token ();
5928  }
5929 }
5930 
5931 /*
5932  * bfmt_print() - Change the given string to a representation of the given bit
5933  * string value in the given format. if this is not long enough to contain
5934  * the new string, then an error is returned.
5935  * return:
5936  * bfmt(in) :
5937  * the_db_bit(in) :
5938  * string(out) :
5939  * max_size(in) : the maximum number of chars that can be stored in
5940  * the string (including final '\0' char)
5941  */
5942 static int
5943 bfmt_print (BIT_STRING_FORMAT * bfmt, const DB_VALUE * the_db_bit, char *string, int max_size)
5944 {
5945  int length = 0;
5946  int string_index = 0;
5947  int byte_index;
5948  int bit_index;
5949  const char *bstring;
5950  int error = NO_ERROR;
5951  static char digits[16] = {
5952  '0', '1', '2', '3', '4', '5', '6', '7',
5953  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
5954  };
5955 
5956  /* Get the buffer and the length from the_db_bit */
5957  bstring = db_get_bit (the_db_bit, &length);
5958 
5959  switch (*bfmt)
5960  {
5961  case BIT_STRING_BINARY:
5962  if (length + 1 > max_size)
5963  {
5964  error = CNV_ERR_STRING_TOO_LONG;
5965  }
5966  else
5967  {
5968  for (byte_index = 0; byte_index < BYTE_COUNT (length); byte_index++)
5969  {
5970  for (bit_index = 7; bit_index >= 0 && string_index < length; bit_index--)
5971  {
5972  *string = digits[((bstring[byte_index] >> bit_index) & 0x1)];
5973  string++;
5974  string_index++;
5975  }
5976  }
5977  *string = '\0';
5978  }
5979  break;
5980 
5981  case BIT_STRING_HEX:
5982  if (BYTE_COUNT_HEX (length) + 1 > max_size)
5983  {
5984  error = CNV_ERR_STRING_TOO_LONG;
5985  }
5986  else
5987  {
5988  for (byte_index = 0; byte_index < BYTE_COUNT (length); byte_index++)
5989  {
5990  *string = digits[((bstring[byte_index] >> BITS_IN_HEX) & 0x0f)];
5991  string++;
5992  string_index++;
5993  if (string_index < BYTE_COUNT_HEX (length))
5994  {
5995  *string = digits[((bstring[byte_index] & 0x0f))];
5996  string++;
5997  string_index++;
5998  }
5999  }
6000  *string = '\0';
6001  }
6002  break;
6003 
6004  default:
6005  assert (!"possible to get here");
6006  break;
6007  }
6008 
6009  return error;
6010 }
6011 
6012 #if defined (ENABLE_UNUSED_FUNCTION)
6013 /* Numeric Format Descriptor Functions */
6014 
6015 /*
6016  * nfmt_integral_value() - Scan tokens and parse an integral value. If a valid
6017  * value can't be found, then return an error condition. otherwise, set
6018  * the_value to the value found.
6019  * return:
6020  * digit_type(in) : the type of digit chars allowed
6021  * ndigits(in) : the maximum number of digits
6022  * sign_required(in) : If this is true, a positive/negative sign
6023  * token must be present
6024  * thousands(in) : If this is true, thousands separators must be included.
6025  * the_value(out) :
6026  */
6027 static int
6028 nfmt_integral_value (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands, char *the_value)
6029 {
6030  int nfound;
6031  int error;
6032 
6033  error = nfmt_integral_digits (digit_type, ndigits, sign_required, thousands, the_value, &nfound);
6034  if (!error && ndigits)
6035  {
6036  /* Too many digits? */
6037  if (nfound > ndigits)
6038  {
6039  error = CNV_ERR_EXTRA_INTEGER;
6041  }
6042  /* Enough digits found? */
6043  else if (digit_type != DIGIT_Z && nfound < ndigits)
6044  {
6045  error = CNV_ERR_MISSING_INTEGER;
6047  }
6048  }
6049 
6050  return error;
6051 }
6052 
6053 /*
6054  * nfmt_integral_digits() - Scan tokens and parse an integral value. If a valid
6055  * value can't be found, then return an error condition. otherwise, set
6056  * the_value to the value found.
6057  * return:
6058  * digit_type(in) : the type of digit chars allowed
6059  * ndigits(in) : the maximum number of digits
6060  * sign_required(in) : If this is true, a positive/negative sign
6061  * token must be present
6062  * thousands(in) : If this is true, thousands separators must be included.
6063  * the_value(out) :
6064  * nfound(out) : The number of digits in the value
6065  */
6066 static int
6067 nfmt_integral_digits (FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands, char *the_value,
6068  int *nfound)
6069 {
6070  int error = 0;
6071 
6072  do
6073  {
6074  FMT_TOKEN_TYPE leading = FT_NONE;
6075  int nleading = 0;
6076  FMT_TOKEN token;
6077  FMT_TOKEN_TYPE type = cnv_fmt_lex (&token);
6078  bool negative = (type == FT_MINUS);
6079 
6080  /* Sign? */
6081  if (negative || (sign_required && type == FT_PLUS))
6082  {
6083  /* Yes, scan next token. */
6084  type = cnv_fmt_lex (&token);
6085  if (type == FT_PLUS || type == FT_MINUS)
6086  {
6087  error = CNV_ERR_EXTRA_SIGN;
6089  break;
6090  }
6091  }
6092  else if (sign_required)
6093  {
6094  cnv_fmt_unlex ();
6095  error = CNV_ERR_NO_SIGN;
6097  break;
6098  }
6099  if (negative)
6100  {
6101  strcpy (the_value, "-");
6102  }
6103  else
6104  {
6105  strcpy (the_value, "");
6106  }
6107 
6108  /* Leading fill chars? */
6109  *nfound = 0;
6110  if (type == FT_ZEROES || type == FT_STARS)
6111  {
6112  /* Yes, scan next token. */
6113  leading = type;
6114  nleading = intl_mbs_len (token.text);
6115  type = cnv_fmt_lex (&token);
6116  }
6117 
6118  /* Any numeric chars left? */
6119  if (type == FT_NUMBER)
6120  {
6121  int initial_digits = 0;
6122  int group_size = *local_grouping ();
6123 
6124  /* Yes, add to numeric value. */
6125  for (; type == FT_NUMBER || type == FT_ZEROES; type = cnv_fmt_lex (&token))
6126  {
6127  int tdigits = intl_mbs_len (token.text);
6128  if (thousands && group_size != CHAR_MAX && ((initial_digits += tdigits) > group_size))
6129  {
6130  error = CNV_ERR_BAD_THOUS;
6132  break;
6133  }
6134  strcat (the_value, token.text);
6135  *nfound += tdigits;
6136  }
6137 
6138  /* Add thousands groups, if necessary. */
6139  if (thousands)
6140  {
6141  for (; type == FT_THOUSANDS; type = cnv_fmt_lex (&token))
6142  {
6143  int tdigits = intl_mbs_len (token.text);
6144  strcat (the_value, token.text);
6145  *nfound += tdigits;
6146  }
6147  if (type == FT_NUMBER || type == FT_ZEROES
6148  || (type == FT_UNKNOWN && mbs_eql (token.text, local_thousands ())))
6149  {
6150  error = CNV_ERR_BAD_THOUS;
6152  break;
6153  }
6154  }
6155  }
6156 
6157  /* Assert: we've scanned following token, so put it back. */
6158  cnv_fmt_unlex ();
6159 
6160  /* Valid leading fill chars? */
6161  if (leading != FT_NONE)
6162  {
6163  if ((leading == FT_STARS && digit_type != DIGIT_STAR) || (leading == FT_ZEROES && !(digit_type == DIGIT_9 ||
6164  /* allow singleton zero. */
6165  (digit_type == DIGIT_Z
6166  && nleading == 1
6167  && *the_value == 0.0))))
6168  {
6169 
6170  error = CNV_ERR_BAD_LEADING;
6172  break;
6173  }
6174  *nfound += nleading;
6175  }
6176  }
6177  while (0);
6178 
6179  return error;
6180 }
6181 
6182 /*
6183  * nfmt_fractional_digits() - Scan tokens and parse fractional value.
6184  * If a valid value can't be found, then return an error condition.
6185  * otherwise, set the_value to the value found.
6186  * return:
6187  * digit_type(in) : the type of digit chars allowed
6188  * ndigits(in) : the maximum number of digits
6189  * the_value(out) :
6190  * nfound(out) : set to the number of digits in the value
6191  */
6192 static int
6193 nfmt_fractional_digits (FORMAT_DIGIT digit_type, int ndigits, char *the_value, int *nfound)
6194 {
6195  int error = 0;
6196 
6197  the_value[0] = '\0';
6198  *nfound = 0;
6199 
6200  do
6201  {
6202  FMT_TOKEN token;
6203  FMT_TOKEN_TYPE type;
6204  FMT_TOKEN_TYPE last = FT_NONE;
6205 
6206  /* Any numeric chars? */
6207  for (; (type = cnv_fmt_lex (&token)) == FT_NUMBER || type == FT_ZEROES; last = type)
6208  {
6209 
6210  /* Yes, add to numeric value. */
6211  int tdigits = intl_mbs_len (token.text);
6212  strcat (the_value, token.text);
6213  *nfound += tdigits;
6214  }
6215 
6216  /* Any trailing fill chars? */
6217  if (type == FT_STARS)
6218  {
6219  if (last != FT_ZEROES)
6220  {
6221  /* Can't have trailing zeroes AND trailing stars! */
6222  last = type;
6223  }
6224  *nfound += intl_mbs_len (token.text);
6225  }
6226  else
6227  {
6228  /* No, retry this token later. */
6229  cnv_fmt_unlex ();
6230  }
6231 
6232  /* Valid trailing fill chars? */
6233  if (last == FT_STARS && digit_type != DIGIT_STAR)
6234  {
6235  error = CNV_ERR_BAD_TRAILING;
6237  break;
6238  }
6239  }
6240  while (0);
6241 
6242  return error;
6243 }
6244 
6245 /*
6246  * nfmt_fractional_value() - Scan tokens and parse fractional value.
6247  * If a valid value can't be found, then return an error condition.
6248  * otherwise, set the_value to the value found.
6249  * return:
6250  * digit_type(in) : the type of digit chars allowed
6251  * ndigits(in) : the maximum number of digits
6252  * the_value(out) :
6253  */
6254 static int
6255 nfmt_fractional_value (FORMAT_DIGIT digit_type, int ndigits, char *the_value)
6256 {
6257  int nfound;
6258  int error;
6259 
6260  error = nfmt_fractional_digits (digit_type, ndigits, the_value, &nfound);
6261 
6262  if (ndigits)
6263  {
6264  /* Too many digits? */
6265  if (nfound > ndigits)
6266  {
6267  error = CNV_ERR_EXTRA_FRACTION;
6269  }
6270 
6271  /* Enough digits found? */
6272  else if (digit_type != DIGIT_Z && nfound < ndigits)
6273  {
6274  error = CNV_ERR_MISSING_FRACTION;
6276  }
6277  }
6278 
6279  return error;
6280 }
6281 
6282 /*
6283  * num_fmt_value() - Get the numeric value represented by the value string.
6284  * Return a pointer to the first char of the string after the last value
6285  * char. If an error occurs, then the value is unchanged and NULL is
6286  * returned.
6287  * return:
6288  * ffmt(in) :
6289  * string(in) :
6290  * the_numeric(out) :
6291  */
6292 static const char *
6293 num_fmt_value (FLOAT_FORMAT * ffmt, const char *string, DB_VALUE * the_numeric)
6294 {
6295  int error = 0;
6296  FMT_TOKEN token;
6297  FMT_TOKEN_TYPE type;
6298  bool decimal_missing = false;
6299  char temp[DEC_BUFFER_SIZE];
6300  int precision;
6301  int scale;
6302  DB_VALUE local_numeric;
6303 
6304  cnv_fmt_analyze (string, FL_LOCAL_NUMBER);
6305 
6306  do
6307  {
6308  /* Get value of integer part. */
6309  error =
6310  nfmt_integral_value (ffmt->integral_type, ffmt->integral_digits, ffmt->sign_required, ffmt->thousands, temp);
6311 
6312  if (error && error != CNV_ERR_MISSING_INTEGER)
6313  {
6314  break;
6315  }
6316 
6317  type = cnv_fmt_lex (&token);
6318  precision = strlen (temp);
6319 
6320  if (ffmt->decimal)
6321  {
6322  /* Decimal point found? */
6323  decimal_missing = (type != FT_DECIMAL);
6324  if (!decimal_missing)
6325  {
6326  char fraction_part[DEC_BUFFER_SIZE];
6327 
6328  if (error)
6329  {
6330  break; /* integer digit really missing. */
6331  }
6332 
6333  /* Yes, get value of fraction part. */
6334  error = nfmt_fractional_value (ffmt->fractional_type, ffmt->fractional_digits, fraction_part);
6335  /*
6336  * Digit really missing? Or did invalid char stop scan prematurely?
6337  * Find out later. Important to ValueEditor to report
6338  * CNV_ERR_MISSING_FRACTION correctly!
6339  */
6340  if (error && error != CNV_ERR_MISSING_FRACTION && error != CNV_ERR_EXTRA_FRACTION)
6341  {
6342  break;
6343  }
6344 
6345  strncat (temp, fraction_part, sizeof (temp) - precision - 1);
6346  precision += strlen (fraction_part);
6347  scale = strlen (fraction_part);
6348  type = cnv_fmt_lex (&token);
6349  numeric_coerce_dec_str_to_num (temp, db_locate_numeric (&local_numeric));
6350  db_make_numeric (the_numeric, db_locate_numeric (&local_numeric), precision, scale);
6351  }
6352  /* No decimal point found. Compute the integer portion */
6353  else
6354  {
6355  numeric_coerce_dec_str_to_num (temp, db_locate_numeric (&local_numeric));
6356  db_make_numeric (the_numeric, db_locate_numeric (&local_numeric), precision, 0);
6357  }
6358  }
6359 
6360  if (type != FT_NONE)
6361  {
6362  /* Invalid chars at the end. */
6363  error = cnv_bad_char (token.raw_text, !ffmt_valid_char (&token));
6364  break;
6365  }
6366 
6367  /* Decimal point missing? */
6368  if (decimal_missing)
6369  {
6370  error = CNV_ERR_NO_DECIMAL;
6372  break;
6373  }
6374  }
6375  while (0);
6376 
6377  return error ? NULL : cnv_fmt_next_token ();
6378 }
6379 #endif
6380 
6381 /*
6382  * num_fmt_print() - Change the given string to a representation of
6383  * the given numeric value in the given format. if max_size is not long
6384  * enough to contain the new numeric string, then an error is returned.
6385  * return:
6386  * ffmt(in) :
6387  * the_numeric(in) :
6388  * string(out) :
6389  * max_size(in) : the maximum number of chars that can be stored in
6390  * the string (including final '\0' char);
6391  */
6392 static int
6393 num_fmt_print (FLOAT_FORMAT * ffmt, const DB_VALUE * the_numeric, char *string, int max_size)
6394 {
6395  int error = 0;
6396  FMT_TOKEN token;
6397  FMT_TOKEN_TYPE type;
6399  int scale;
6400  int position;
6401  const char *dp;
6402  char num_dec_digits[DEC_BUFFER_SIZE];
6403  int integral_start_pos = 0;
6404 
6405  /* Copy the numeric decimal digits into the buffer in the default format */
6406  scale = DB_VALUE_SCALE (the_numeric);
6407  numeric_coerce_num_to_dec_str (db_locate_numeric ((DB_VALUE *) the_numeric), num_dec_digits);
6408  sprintf ((char *) adj_ar_get_buffer (buffer), "%s", num_dec_digits);
6409 
6410  /* Add the decimal point */
6411  if (scale > 0)
6412  {
6413  position = strlen (num_dec_digits) - scale;
6414  dp = local_decimal ();
6415  adj_ar_insert (buffer, dp, strlen (dp), position);
6416  }
6417 
6418  /* Trim leading zeroes */
6419  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
6420  while ((type = cnv_fmt_lex (&token)) == FT_MINUS || type == FT_PLUS)
6421  integral_start_pos++;
6422  if (type == FT_ZEROES)
6423  {
6424  adj_ar_remove (buffer, integral_start_pos,
6425  CAST_STRLEN (cnv_fmt_next_token () - (char *) adj_ar_get_buffer (buffer)));
6426  }
6427 
6428  /* Trim leading blanks... */
6429  if (!ffmt->integral_digits || ffmt->integral_type == DIGIT_Z)
6430  {
6431  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
6432  while (cnv_fmt_lex (&token) == FT_UNKNOWN && mbs_eql (token.text, LOCAL_SPACE));
6433  adj_ar_remove (buffer, 0,
6434  CAST_STRLEN (cnv_fmt_next_token () - token.length - (char *) adj_ar_get_buffer (buffer)));
6435  }
6436 
6437  /* ...or replace with leading stars. */
6438  else if (ffmt->integral_type == DIGIT_STAR)
6439  {
6440  int start;
6441 
6442  cnv_fmt_analyze ((const char *) adj_ar_get_buffer (buffer), FL_LOCAL_NUMBER);
6443  while ((type = cnv_fmt_lex (&token)) == FT_MINUS || type == FT_PLUS);
6444  start = CAST_STRLEN (cnv_fmt_next_token () - token.length - (const char *) adj_ar_get_buffer (buffer));
6445 
6446  if (type == FT_ZEROES)
6447  {
6448  int nzeroes;
6449  int sl = strlen (LOCAL_STAR);
6450  adj_ar_remove (buffer, start, start + token.length);
6451  for (nzeroes = intl_mbs_len (token.text); nzeroes > 0; nzeroes--)
6452  {
6453  adj_ar_insert (buffer, LOCAL_STAR, sl, start);
6454  }
6455  }
6456  }
6457 
6458 #if defined (ENABLE_UNUSED_FUNCTION)
6459  /* Add thousands separators. */
6460  if (ffmt->thousands)
6461  {
6462  fmt_add_thousands (buffer, NULL);
6463  }
6464 #endif
6465 
6466  /* Enough room to copy completed value string? */
6467  if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
6468  {
6469  error = CNV_ERR_STRING_TOO_LONG;
6470  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
6471  }
6472 
6473  else
6474  {
6475  strcpy (string, (char *) adj_ar_get_buffer (buffer));
6476  if (strlen (string) == 0)
6477  {
6478  strcpy (string, "0");
6479  }
6480  }
6481 
6482  return error;
6483 }
6484 
6485 
6486 /* Conversion Functions */
6487 /*
6488  * db_string_value() - Change the given value to the result of converting
6489  * the value string in the given format. Return a pointer to the first
6490  * char of the string after the last value char. The string and format must
6491  * be valid for the type of the given value. If an error occurs, then
6492  * the value is unchanged and NULL is returned.
6493  * return:
6494  * string(in) :
6495  * str_size(in) :
6496  * format(in) :
6497  * value(out) :
6498  *
6499  */
6500 const char *
6501 db_string_value (const char *string, int str_size, const char *format, DB_VALUE * value)
6502 {
6503  const char *next = NULL;
6504 
6505  assert (string != NULL);
6506  assert (value != NULL);
6507 
6508  /* Empty string is always NULL value. */
6509  if (!strlen (string))
6510  {
6512  next = string;
6513  }
6514  else
6515  {
6516  switch (DB_VALUE_DOMAIN_TYPE (value))
6517  {
6518  case DB_TYPE_DATE:
6519  {
6520  DB_DATE date = 0;
6521 
6523  {
6524  return NULL;
6525  }
6526 
6527  if (db_string_to_date (string, &date) == NO_ERROR)
6528  {
6529  db_value_put_encoded_date (value, &date);
6530  next = string;
6531  }
6532 
6534  break;
6535  }
6536 
6537  case DB_TYPE_DOUBLE:
6538  {
6539  double num;
6541  {
6542  return NULL;
6543  }
6544 
6545  if ((next = db_string_double (string, format, &num)))
6546  {
6547  db_make_double (value, num);
6548  }
6549 
6551  break;
6552  }
6553 
6554  case DB_TYPE_FLOAT:
6555  {
6556  float num;
6558  {
6559  return NULL;
6560  }
6561 
6562  if ((next = db_string_float (string, format, &num)))
6563  {
6564  db_make_float (value, num);
6565  }
6566 
6568  break;
6569  }
6570 
6571  case DB_TYPE_INTEGER:
6572  {
6573  int num;
6575  {
6576  return NULL;
6577  }
6578 
6579  if ((next = db_string_integer (string, format, &num)))
6580  {
6581  db_make_int (value, num);
6582  }
6583 
6585  break;
6586  }
6587 
6588  case DB_TYPE_BIGINT:
6589  {
6590  DB_BIGINT num;
6592  {
6593  return NULL;
6594  }
6595 
6596  if ((next = db_string_bigint (string, format, &num)))
6597  {
6598  db_make_bigint (value, num);
6599  }
6600 
6602  break;
6603  }
6604 
6605  case DB_TYPE_MONETARY:
6606  /* Check for valid currency. If not, set it to the default */
6608  {
6609  db_make_monetary (value, DB_CURRENCY_DEFAULT, 0.0);
6610  }
6611  /* Extract the initialized monetary field and convert */
6613  {
6614  return NULL;
6615  }
6616  next = db_string_monetary (string, format, db_get_monetary (value));
6618  break;
6619 
6620  case DB_TYPE_NULL:
6621  if (strlen (string))
6622  {
6624  }
6625  else
6626  {
6627  next = string;
6628  }
6629  break;
6630 
6631  case DB_TYPE_SHORT:
6632  {
6633  short the_short;
6635  {
6636  return NULL;
6637  }
6638 
6639  if ((next = db_string_short (string, format, &the_short)))
6640  {
6641  db_make_short (value, the_short);
6642  }
6643 
6645  break;
6646  }
6647 
6648  case DB_TYPE_CHAR:
6649  {
6650  int size = strlen (string);
6651  db_make_char (value, size, string, size, LANG_SYS_CODESET, LANG_SYS_COLLATION);
6652  next = string + size;
6653  break;
6654  }
6655 
6656  case DB_TYPE_VARCHAR:
6657  {
6658  int size = strlen (string);
6659  db_make_varchar (value, size, string, size, LANG_SYS_CODESET, LANG_SYS_COLLATION);
6660  next = string + size;
6661  break;
6662  }
6663 
6664  case DB_TYPE_NCHAR:
6665  {
6666  int size;
6667  intl_char_count ((unsigned char *) string, strlen (string), LANG_SYS_CODESET, &size);
6668  db_make_nchar (value, size, string, size, LANG_SYS_CODESET, LANG_SYS_COLLATION);
6669  next = string + strlen (string);
6670  break;
6671  }
6672 
6673  case DB_TYPE_VARNCHAR:
6674  {
6675  int char_count;
6676  intl_char_count ((unsigned char *) string, strlen (string), LANG_SYS_CODESET, &char_count);
6677  db_make_varnchar (value, char_count, string, char_count, LANG_SYS_CODESET, LANG_SYS_COLLATION);
6678  next = string + strlen (string);
6679  break;
6680  }
6681 
6682  case DB_TYPE_TIME:
6683  {
6684  DB_TIME time;
6686  {
6687  return NULL;
6688  }
6689 
6690  if (db_string_to_time (string, &time) == NO_ERROR)
6691  {
6692  db_value_put_encoded_time (value, &time);
6693  next = string;
6694  }
6695 
6697  break;
6698  }
6699 
6700  case DB_TYPE_TIMESTAMP:
6701  {
6702  DB_TIMESTAMP timestamp;
6704  {
6705  return NULL;
6706  }
6707 
6708  if (db_string_to_timestamp (string, &timestamp) == NO_ERROR)
6709  {
6710  db_make_timestamp (value, timestamp);
6711  next = string;
6712  }
6713 
6715  break;
6716  }
6717 
6718  case DB_TYPE_DATETIME:
6719  {
6720  DB_DATETIME datetime;
6722  {
6723  return NULL;
6724  }
6725 
6726  if (db_string_to_datetime (string, &datetime) == NO_ERROR)
6727  {
6728  db_make_datetime (value, &datetime);
6729  next = string;
6730  }
6731 
6733  break;
6734  }
6735 
6736  case DB_TYPE_VARBIT:
6737  case DB_TYPE_BIT:
6739  {
6740  return NULL;
6741  }
6742  next = db_string_bit (string, format, value);
6744  break;
6745 
6746  case DB_TYPE_NUMERIC:
6747 #if defined (ENABLE_UNUSED_FUNCTION)
6749  {
6750  return NULL;
6751  }
6752  next = db_string_numeric (string, format, value);
6754  break;
6755 #endif
6756  case DB_TYPE_BLOB:
6757  case DB_TYPE_CLOB:
6758  case DB_TYPE_ERROR:
6759  case DB_TYPE_DB_VALUE:
6760  case DB_TYPE_OBJECT:
6761  case DB_TYPE_OID:
6762  case DB_TYPE_POINTER:
6763  case DB_TYPE_SET:
6764  case DB_TYPE_MULTISET:
6765  case DB_TYPE_SEQUENCE:
6766  case DB_TYPE_SUB:
6767  case DB_TYPE_VARIABLE:
6768  case DB_TYPE_VOBJ:
6770  break;
6771  default:
6772  co_signal (CNV_ERR_BAD_TYPE, CNV_ER_FMT_BAD_TYPE, "UNKNWON TYPE");
6773  break;
6774  }
6775  }
6776 
6777  return next;
6778 }
6779 
6780 #if defined (ENABLE_UNUSED_FUNCTION)
6781 /*
6782  * db_string_to_value() - Return a value of the specified type by converting
6783  * the value string in the given format. If an error occurs, then return NULL.
6784  * This function is equivalent to db_string_value, except that the value
6785  * is allocated automatically.
6786  * return:
6787  * string(in) :
6788  * format(in) :
6789  *
6790  * note : If type is DB_TYPE_MONETARY, then an additional DB_CURRENCY arg
6791  * must be given. otherwise, optional args are ignored.
6792  * The contents of the returned value must not be freed. The
6793  * contents of the returned value may be changed by calls to other
6794  * conversion functions.
6795  */
6796 DB_VALUE *
6797 db_string_to_value (const char *string, const char *format, DB_TYPE type, ...)
6798 {
6799  va_list args;
6800  static DB_VALUE value;
6801  DB_CURRENCY currency;
6802 
6804  if (type == DB_TYPE_MONETARY)
6805  {
6806  va_start (args, type);
6807  currency = va_arg (args, DB_CURRENCY);
6808  db_make_monetary (&value, currency, 0.0);
6809  va_end (args);
6810  }
6811 
6812  return db_string_value (string, format, &value) ? &value : NULL;
6813 }
6814 
6815 /*
6816  * db_value_string() - Change the given string to a representation of
6817  * the given value in the given format. If an error occurs, then the
6818  * contents of the string are undefined and an error condition is returned.
6819  * if max_size is not long enough to contain the new string, then an error
6820  * is returned.
6821  * return:
6822  * value(in) :
6823  * format(in) :
6824  * string(out) :
6825  * max_size(in) : the maximum number of chars that can be stored in the string
6826  * (including final '\0' char)
6827  *
6828  */
6829 int
6830 db_value_string (const DB_VALUE * value, const char *format, char *string, int max_size)
6831 {
6832  int error = 0;
6833  int dummy;
6834  char *p;
6835 
6836  assert (value != NULL);
6837  assert (string != NULL);
6838  assert (max_size > 0);
6839 
6840  switch (DB_VALUE_TYPE (value))
6841  {
6842  case DB_TYPE_DATE:
6843  error = db_date_string (db_get_date (value), format, string, max_size);
6844  break;
6845 
6846  case DB_TYPE_NUMERIC:
6847  error = db_numeric_string (value, format, string, max_size);
6848  break;
6849 
6850  case DB_TYPE_DOUBLE:
6851  error = db_double_string (db_get_double (value), format, string, max_size);
6852  break;
6853 
6854  case DB_TYPE_FLOAT:
6855  error = db_float_string (db_get_float (value), format, string, max_size);
6856  break;
6857 
6858  case DB_TYPE_INTEGER:
6859  error = db_integer_string (db_get_int (value), format, string, max_size);
6860  break;
6861  case DB_TYPE_BIGINT:
6862  error = db_bigint_string (db_get_bigint (value), format, string, max_size);
6863  break;
6864 
6865  case DB_TYPE_MONETARY:
6866  error = db_monetary_string (db_get_monetary (value), format, string, max_size);
6867  break;
6868 
6869  case DB_TYPE_NULL:
6870  strcpy (string, "");
6871  break;
6872 
6873  case DB_TYPE_SHORT:
6874  error = db_short_string (db_get_short (value), format, string, max_size);
6875  break;
6876 
6877  case DB_TYPE_VARCHAR:
6878  case DB_TYPE_CHAR:
6879  p = db_get_char (value, &dummy);
6880 
6881  if (p == NULL)
6882  {
6883  break;
6884  }
6885 
6886  if ((int) strlen (p) + 1 > max_size)
6887  {
6888  error = CNV_ERR_STRING_TOO_LONG;
6889  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
6890  }
6891  else
6892  {
6893  strcpy (string, p);
6894  }
6895  break;
6896 
6897  case DB_TYPE_VARNCHAR:
6898  case DB_TYPE_NCHAR:
6899  p = db_get_nchar (value, &dummy);
6900  if (p != NULL)
6901  {
6902  if ((int) strlen (p) + 1 > max_size)
6903  {
6904  error = CNV_ERR_STRING_TOO_LONG;
6905  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
6906  }
6907  else
6908  {
6909  strcpy (string, p);
6910  }
6911  }
6912  break;
6913 
6914  case DB_TYPE_TIME:
6915  error = db_time_string (db_get_time (value), format, string, max_size);
6916  break;
6917 
6918  case DB_TYPE_TIMESTAMP:
6919  error = db_timestamp_string (db_get_timestamp (value), format, string, max_size);
6920  break;
6921 
6922  case DB_TYPE_DATETIME:
6923  error = db_datetime_string (db_get_datetime (value), format, string, max_size);
6924  break;
6925  case DB_TYPE_VARBIT:
6926  case DB_TYPE_BIT:
6927  error = db_bit_string (value, format, string, max_size);
6928  break;
6929 
6930  case DB_TYPE_BLOB:
6931  case DB_TYPE_CLOB:
6932  case DB_TYPE_ERROR:
6933  case DB_TYPE_DB_VALUE:
6934  case DB_TYPE_OBJECT:
6935  case DB_TYPE_OID:
6936  case DB_TYPE_POINTER:
6937  case DB_TYPE_SET:
6938  case DB_TYPE_MULTISET:
6939  case DB_TYPE_SEQUENCE:
6940  case DB_TYPE_SUB:
6941  case DB_TYPE_VARIABLE:
6942  case DB_TYPE_VOBJ:
6943  error = CNV_ERR_BAD_TYPE;
6945  break;
6946 
6947  default:
6948  error = CNV_ERR_BAD_TYPE;
6949  co_signal (error, CNV_ER_FMT_BAD_TYPE, "UNKNWON TYPE");
6950  break;
6951  }
6952 
6953  return error;
6954 }
6955 #endif
6956 
6957 #if !defined(SERVER_MODE)
6958 #if defined(ENABLE_UNUSED_FUNCTION)
6959 /*
6960  * db_value_to_string() - Return a string representing the given value in
6961  * the given format. If an error occurs, then return NULL.
6962  * This function is equivalent to db_value_string, except that the value
6963  * string is allocated automatically.
6964  * return:
6965  * value(in) :
6966  * format(in) :
6967  */
6968 const char *
6969 db_value_to_string (const DB_VALUE * value, const char *format)
6970 {
6971  static char *buffer;
6972  static int max_size = 0;
6973 
6974  int error;
6975 
6976  assert (value != NULL);
6977 
6978  if (max_size == 0)
6979  {
6980  /* Initialize buffer. */
6981  max_size = 32;
6982  if ((buffer = (char *) malloc (max_size)) == NULL)
6983  {
6984  return NULL;
6985  }
6986  }
6987 
6988  /* Reallocate buffer until big enough. */
6989  while ((error = db_value_string (value, format, buffer, max_size)) == CNV_ERR_STRING_TOO_LONG)
6990  {
6991  max_size += max_size / 2; /* Grow by 1.5x */
6992  static char *const realloc_buffer = (char *) realloc (buffer, max_size);
6993  if (realloc_buffer == NULL)
6994  {
6995  return NULL;
6996  }
6997  else
6998  {
6999  buffer = realloc_buffer;
7000  }
7001  }
7002 
7003  return error ? NULL : (const char *) buffer;
7004 }
7005 #endif /* ENABLE_UNUSED_FUNCTION */
7006 #endif /* !SERVER_MODE */
7007 
7008 /*
7009  * db_string_date() - Change the date value to the result of converting
7010  * the date string in the given format. Return a pointer to the first
7011  * char of the string after the last value char. If an error occurs,
7012  * then the value is unchanged and NULL is returned.
7013  * return:
7014  * date_string(in) :
7015  * date_format(in) :
7016  * the_date(out) :
7017  */
7018 const char *
7019 db_string_date (const char *date_string, const char *date_format, DB_DATE * the_date)
7020 {
7021  const FMT_TOKEN *fmt_token;
7022  int month;
7023  int day;
7024  int year;
7025  int error = 0;
7026 #if defined (ENABLE_UNUSED_FUNCTION)
7027  int wday;
7028  const char *value_string;
7029  int i;
7030 #endif
7031 
7032  assert (the_date != NULL);
7033  assert (date_string != NULL);
7034 
7035  /* Initialize to given date. */
7036  db_date_decode (the_date, &month, &day, &year);
7037 
7038  /* Scan value string according to format. */
7039  for (fmt_token = tfmt_new (strlen (date_format) ? date_format : "%x"), cnv_fmt_analyze (date_string, FL_LOCAL_TIME);
7040  !error && fmt_token->type != FT_NONE; fmt_token++)
7041  {
7042 
7043  switch (fmt_token->type)
7044  {
7045 
7046  case FT_DATE:
7047  error = fmt_date_value (fmt_token->text, &month, &day, &year);
7048  break;
7049 
7050 #if defined (ENABLE_UNUSED_FUNCTION)
7051  case FT_PATTERN:
7052  /* Pattern string found in value string? */
7053  value_string = cnv_fmt_next_token ();
7054  if (!strncmp (fmt_token->text, value_string, fmt_token->length))
7055  {
7056 
7057  /* Yes, restart scan after pattern. */
7058  cnv_fmt_analyze (value_string + fmt_token->length, FL_LOCAL_TIME);
7059  }
7060  else
7061  {
7062  /* No, signal error showing where mismatch occurs. */
7063  for (i = fmt_token->length - 1; i > 0 && strncmp (fmt_token->text, value_string, i); i--);
7064  error = CNV_ERR_BAD_PATTERN;
7065  co_signal (error, CNV_ER_FMT_BAD_PATTERN, fmt_token->text + i, value_string - date_string + i);
7066  }
7067  break;
7068 
7069  case FT_YEAR:
7070  error = fmt_year_value (fmt_token->text, &year);
7071  break;
7072 
7073  case FT_MONTH:
7074  error = fmt_month_value (fmt_token->text, &month);
7075  break;
7076 
7077  case FT_MONTHDAY:
7078  error = fmt_monthday_value (fmt_token->text, &day);
7079  break;
7080 
7081  case FT_WEEKDAY:
7082  error = fmt_weekday_value (fmt_token->text, &wday);
7083  if (!error)
7084  {
7085  DB_DATE new_date = fmt_weekday_date (month, day, year, wday);
7086  db_date_decode (&new_date, &month, &day, &year);
7087  }
7088  break;
7089 #endif
7090  default:
7091  assert (!"possible to get here");
7092  }
7093  }
7094 
7095  if (!error)
7096  {
7097  int m, d, y;
7098 
7099  /* Is this a bogus date like 9/31? */
7100  error = db_date_encode (the_date, month, day, year);
7101  if (error != NO_ERROR)
7102  {
7103  error = CNV_ERR_UNKNOWN_DATE;
7104  co_signal (error, CNV_ER_FMT_UNKNOWN_DATE, local_date_string (month, day, year));
7105  goto function_end;
7106  }
7107  db_date_decode (the_date, &m, &d, &y);
7108  if (!(month == m && day == d && year == y))
7109  {
7110  error = CNV_ERR_UNKNOWN_DATE;
7111  co_signal (error, CNV_ER_FMT_UNKNOWN_DATE, local_date_string (month, day, year));
7112  }
7113  }
7114 
7115 function_end:
7116  return error ? NULL : cnv_fmt_next_token ();
7117 }
7118 
7119 #if defined (ENABLE_UNUSED_FUNCTION)
7120 /*
7121  * db_date_string() - Change the given string to a representation of
7122  * the given date value in the given format. If an error occurs, then
7123  * the contents of the string are undefined and an error condition is
7124  * returned. if max_size is not long enough to contain the new date
7125  * string, then an error is returned.
7126  * return:
7127  * the_date(in) :
7128  * date_format(in) :
7129  * string(out) :
7130  * max_size(in) : the maximum number of chars that can be stored in
7131  * the string (including final '\0' char).
7132  */
7133 int
7134 db_date_string (const DB_DATE * the_date, const char *date_format, char *string, int max_size)
7135 {
7136  int error = 0;
7137  ADJ_ARRAY *buffer = cnv_get_value_string_buffer (0);
7138  FMT_TOKEN_TYPE ttype;
7139  FMT_TOKEN token;
7140  const char *value_string;
7141  int month, day, year, weekday;
7142 
7143  assert (the_date != NULL);
7144  assert (string != NULL);
7145  assert (max_size > 0);
7146 
7147  error = csect_enter (NULL, CSECT_CNV_FMT_LEXER, INF_WAIT); /* before using lexer */
7148  if (error != NO_ERROR)
7149  {
7150  return error;
7151  }
7152 
7153  db_date_decode ((DB_DATE *) the_date, &month, &day, &year);
7154 
7155  /* Print according to format. */
7156  for (cnv_fmt_analyze (strlen (date_format) ? date_format : "%x", FL_TIME_FORMAT);
7157  (ttype = cnv_fmt_lex (&token)) != FT_NONE; adj_ar_append (buffer, value_string, strlen (value_string)))
7158  {
7159 
7160  switch (ttype)
7161  {
7162  case FT_DATE:
7163  value_string = fmt_date_string (the_date, token.text);
7164  break;
7165 
7166 #if defined (ENABLE_UNUSED_FUNCTION)
7167  case FT_PATTERN:
7168  value_string = token.text;
7169  break;
7170 
7171  case FT_YEAR:
7172  value_string = fmt_year_string (year, token.text);
7173  break;
7174  case FT_MONTH:
7175  value_string = fmt_month_string (month, token.text);
7176  break;
7177 
7178  case FT_MONTHDAY:
7179  value_string = fmt_monthday_string (day, token.text);
7180  break;
7181  case FT_WEEKDAY:
7182  weekday = db_date_weekday ((DB_DATE *) the_date);
7183  value_string = fmt_weekday_string (weekday, token.text);
7184  break;
7185 #endif
7186  default:
7187  assert (!"possible to get here");
7188  value_string = "";
7189  break;
7190  }
7191  }
7192 
7193  csect_exit (NULL, CSECT_CNV_FMT_LEXER); /* after using lexer */
7194 
7195  adj_ar_append (buffer, "", 1);
7196 
7197  /* Enough room to copy completed value string? */
7198  if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
7199  {
7200  error = CNV_ERR_STRING_TOO_LONG;
7201  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
7202  }
7203  else
7204  {
7205  strcpy (string, (char *) adj_ar_get_buffer (buffer));
7206  }
7207 
7208  return error;
7209 }
7210 #endif
7211 
7212 /*
7213  * db_string_double() - Change the double value to the result of converting
7214  * the double string in the given format. Return a pointer to the first
7215  * char of the string after the last value char. If an error occurs, then
7216  * the value is unchanged and NULL is returned.
7217  * return:
7218  * double_string(in) :
7219  * double_format(in) :
7220  * the_double(out) :
7221  */
7222 const char *
7223 db_string_double (const char *double_string, const char *double_format, double *the_double)
7224 {
7225  FLOAT_FORMAT ffmt;
7226 
7227  assert (the_double != NULL);
7228  assert (double_string != NULL);
7229 
7230  ffmt_new (&ffmt, double_format);
7231  if (!strchr (double_string, '.'))
7232  {
7233  ffmt.decimal = 0;
7234  }
7235  return ffmt_value (&ffmt, double_string, the_double);
7236 }
7237 
7238 #if defined (ENABLE_UNUSED_FUNCTION)
7239 /*
7240  * db_double_string() - Change the given string to a representation of
7241  * the given double value in the given format. If an error occurs, then
7242  * the contents of the string are undefined and an error condition
7243  * is returned. if max_size is not long enough to contain the new double
7244  * string, then an error is returned.
7245  * return:
7246  * the_double(in) :
7247  * double_format(in) :
7248  * string(out) :
7249  * max_size(in) : the maximum number of chars that can be stored in
7250  * the string (including final '\0' char).
7251  */
7252 int
7253 db_double_string (double the_double, const char *double_format, char *string, int max_size)
7254 {
7255  FLOAT_FORMAT ffmt;
7256  int r;
7257 
7258  assert (string != NULL);
7259  assert (max_size > 0);
7260 
7262  if (r != NO_ERROR)
7263  {
7264  return r;
7265  }
7266 
7267  ffmt_new (&ffmt, double_format);
7268  r = ffmt_print (&ffmt, the_double, string, max_size);
7269 
7271 
7272  return r;
7273 }
7274 
7275 /*
7276  * db_string_numeric() - Change the numeric value to the result of converting
7277  * the numeric string in the given format. Return a pointer to the first
7278  * char of the string after the last value char. If an error occurs, then
7279  * the value is unchanged and NULL is returned.
7280  * return: a pointer to the first char of the string after the last value char.
7281  * error code :
7282  * CNV_ERR_MISSING_INTEGER Not enough digits in integer part
7283  * CNV_ERR_MISSING_FRACTION Not enough digits in fraction part
7284  * CNV_ERR_NO_DECIMAL Missing decimal point
7285  *
7286  * numeric_string(in) :
7287  * numeric_format(in) :
7288  * the_numeric(out) :
7289  */
7290 const char *
7291 db_string_numeric (const char *numeric_string, const char *numeric_format, DB_VALUE * the_numeric)
7292 {
7293  FLOAT_FORMAT ffmt;
7294 
7295  assert (the_numeric != NULL);
7296  assert (numeric_string != NULL);
7297 
7298  ffmt_new (&ffmt, numeric_format);
7299  return num_fmt_value (&ffmt, numeric_string, the_numeric);
7300 }
7301 #endif
7302 
7303 /*
7304  * db_numeric_string() - Change the given string to a representation of
7305  * the given numeric value in the given format. If an error occurs,
7306  * then the contents of the string are undefined and an error condition
7307  * is returned. if max_size is not long enough to contain the new numeric
7308  * string, then an error is returned.
7309  * return:
7310  * the_numeric(in) :
7311  * numeric_format(in) :
7312  * string(out) :
7313  * max_size(in) : the maximum number of chars that can be stored in
7314  * the string (including final '\0' char).
7315  */
7316 int
7317 db_numeric_string (const DB_VALUE * the_numeric, const char *numeric_format, char *string, int max_size)
7318 {
7319  FLOAT_FORMAT ffmt;
7320  int r;
7321 
7322  assert (string != NULL);
7323  assert (max_size > 0);
7324 
7326  if (r != NO_ERROR)
7327  {
7328  return r;
7329  }
7330 
7331  ffmt_new (&ffmt, numeric_format);
7332  r = num_fmt_print (&ffmt, the_numeric, string, max_size);
7333 
7335 
7336  return r;
7337 }
7338 
7339 /*
7340  * db_string_float() - Change the float value to the result of converting
7341  * the float string in the given format. Return a pointer to the first
7342  * char of the string after the last value char. If an error occurs,
7343  * then the value is unchanged and NULL is returned.
7344  * return:
7345  * error code:
7346  * CNV_ERR_MISSING_INTEGER Not enough digits in integer part
7347  * CNV_ERR_MISSING_FRACTION Not enough digits in fraction part
7348  * CNV_ERR_NO_DECIMAL Missing decimal point
7349  * CNV_ERR_FLOAT_OVERFLOW Float value too large
7350  * CNV_ERR_FLOAT_UNDERFLOW Float value too small
7351  *
7352  * float_string(in) :
7353  * float_format(in) :
7354  * the_float(out) :
7355  */
7356 const char *
7357 db_string_float (const char *float_string, const char *float_format, float *the_float)
7358 {
7359  FLOAT_FORMAT ffmt;
7360  const char *endp;
7361  double the_double;
7362 
7363  assert (the_float != NULL);
7364  assert (float_string != NULL);
7365 
7366  ffmt_new (&ffmt, float_format);
7367  if (!strchr (float_string, '.'))
7368  {
7369  ffmt.decimal = 0;
7370  }
7371  endp = ffmt_value (&ffmt, float_string, &the_double);
7372 
7373  if (endp)
7374  {
7375  if (the_double > FLT_MAX)
7376  {
7378  endp = NULL;
7379  }
7380  else if (the_double < -FLT_MAX)
7381  {
7383  endp = NULL;
7384  }
7385  else
7386  {
7387  *the_float = (float) the_double;
7388  }
7389  }
7390  return endp;
7391 
7392 }
7393 
7394 #if defined (ENABLE_UNUSED_FUNCTION)
7395 /*
7396  * db_float_string() - Change the given string to a representation of the given
7397  * float value in the given format. If an error occurs, then the contents of
7398  * the string are undefined and an error condition is returned.
7399  * if max_size is not long enough to contain the new float string, then an
7400  * error is returned.
7401  * return:
7402  * the_float(in) :
7403  * float_format(in) :
7404  * string(out) :
7405  * max_size(in) : the maximum number of chars that can be stored in
7406  * the string (including final '\0' char)
7407  */
7408 int
7409 db_float_string (float the_float, const char *float_format, char *string, int max_size)
7410 {
7411  FLOAT_FORMAT ffmt;
7412  int r;
7413 
7414  assert (string != NULL);
7415  assert (max_size > 0);
7416 
7418  if (r != NO_ERROR)
7419  {
7420  return r;
7421  }
7422 
7423  ffmt_new (&ffmt, float_format);
7424  r = ffmt_print (&ffmt, the_float, string, max_size);
7425 
7427 
7428  return r;
7429 }
7430 #endif
7431 
7432 /*
7433  * db_string_integer() - Change the integer value to the result of converting
7434  * the integer string in the given format. Return a pointer to the first
7435  * char of the string after the last value char. If an error occurs, then
7436  * the value is unchanged and NULL is returned.
7437  * return:
7438  * integer_string(in) :
7439  * integer_format(in) :
7440  * the_integer(out) :
7441  */
7442 const char *
7443 db_string_integer (const char *integer_string, const char *integer_format, int *the_integer)
7444 {
7445  INTEGER_FORMAT ifmt;
7446 
7447  assert (the_integer != NULL);
7448  assert (integer_string != NULL);
7449 
7450  ifmt_new (&ifmt, integer_format);
7451  return ifmt_value (&ifmt, integer_string, the_integer);
7452 }
7453 
7454 #if defined (ENABLE_UNUSED_FUNCTION)
7455 /*
7456  * db_integer_string() - Change the given string to a representation of the
7457  * given integer value in the given format. If an error occurs, then the
7458  * contents of the string are undefined and an error condition is returned.
7459  * if max_size is not long enough to contain the new float string, then an
7460  * error is returned.
7461  * return:
7462  * the_integer(in) :
7463  * integer_format(in) :
7464  * string(out) :
7465  * max_size(in) : the maximum number of chars that can be stored in
7466  * the string (including final '\0' char)
7467  */
7468 int
7469 db_integer_string (int the_integer, const char *integer_format, char *string, int max_size)
7470 {
7471  INTEGER_FORMAT ifmt;
7472  int r;
7473 
7474  assert (string != NULL);
7475  assert (max_size > 0);
7476 
7478  if (r != NO_ERROR)
7479  {
7480  return r;
7481  }
7482 
7483  ifmt_new (&ifmt, integer_format);
7484  r = ifmt_print (&ifmt, the_integer, string, max_size);
7485 
7487 
7488  return r;
7489 }
7490 #endif
7491 
7492 /*
7493  * db_string_bigint() - Change the big integer value to the result of converting
7494  * the integer string in the given format. Return a pointer to the first
7495  * char of the string after the last value char. If an error occurs, then
7496  * the value is unchanged and NULL is returned.
7497  * return:
7498  * bitint_string(in) :
7499  * bigint_format(in) :
7500  * the_bigint(out) :
7501  */
7502 const char *
7503 db_string_bigint (const char *bitint_string, const char *bigint_format, DB_BIGINT * the_bigint)
7504 {
7505  INTEGER_FORMAT ifmt;
7506 
7507  assert (the_bigint != NULL);
7508  assert (bitint_string != NULL);
7509 
7510  ifmt_new (&ifmt, bigint_format);
7511  return bifmt_value (&ifmt, bitint_string, the_bigint);
7512 }
7513 
7514 #if defined (ENABLE_UNUSED_FUNCTION)
7515 /*
7516  * db_bigint_string() - Change the given string to a representation of the
7517  * given big integer value in the given format. If an error occurs, then the
7518  * contents of the string are undefined and an error condition is returned.
7519  * if max_size is not long enough to contain the new float string, then an
7520  * error is returned.
7521  * return:
7522  * the_bigint(in) :
7523  * bigint_format(in) :
7524  * string(out) :
7525  * max_size(in) : the maximum number of chars that can be stored in
7526  * the string (including final '\0' char)
7527  */
7528 int
7529 db_bigint_string (DB_BIGINT the_bigint, const char *bigint_format, char *string, int max_size)
7530 {
7531  INTEGER_FORMAT ifmt;
7532  int r;
7533 
7534  assert (string != NULL);
7535  assert (max_size > 0);
7536 
7538  if (r != NO_ERROR)
7539  {
7540  return r;
7541  }
7542 
7543  ifmt_new (&ifmt, bigint_format);
7544  r = ifmt_print (&ifmt, the_bigint, string, max_size);
7545 
7547 
7548  return r;
7549 }
7550 #endif
7551 
7552 /*
7553  * db_string_monetary() - Change the monetary value to the result of converting
7554  * the monetary string in the given format. Return a pointer to the first
7555  * char of the string after the last value char. If an error occurs, then
7556  * the value is unchanged and NULL is returned.
7557  * return:
7558  * error code :
7559  * CNV_ERR_NO_CURRENCY Missing required currency symbol
7560  * CNV_ERR_MISSING_INTEGER Not enough digits in integer part
7561  * CNV_ERR_MISSING_FRACTION Not enough digits in fraction part
7562  * CNV_ERR_NO_DECIMAL Missing decimal point
7563  *
7564  * monetary_string(in) :
7565  * monetary_format(in) :
7566  * the_monetary(out) :
7567  *
7568  * note : the currency type of the_monetary determines the currency symbol
7569  * allowed in the monetary_string.
7570  */
7571 const char *
7572 db_string_monetary (const char *monetary_string, const char *monetary_format, DB_MONETARY * the_monetary)
7573 {
7574  MONETARY_FORMAT mfmt;
7575 
7576  assert (the_monetary != NULL);
7577  assert (monetary_string != NULL);
7578  assert (cnv_valid_currency (the_monetary->type));
7579 
7580  mfmt_new (&mfmt, monetary_format, the_monetary->type);
7581  return mfmt_value (&mfmt, monetary_string, &(the_monetary->amount));
7582 }
7583 
7584 #if defined (ENABLE_UNUSED_FUNCTION)
7585 /*
7586  * db_monetary_string() - Change the given string to a representation of
7587  * the given monetary value in the given format. If an error occurs, then
7588  * the contents of the string are undefined and an error condition is
7589  * returned.
7590  * if max_size is not long enough to contain the new float string, then an
7591  * error is returned.
7592  * return:
7593  * the_monetary(in) :
7594  * monetary_format(in) :
7595  * string(out) :
7596  * max_size(in) : the maximum number of chars that can be stored in
7597  * the string (including final '\0' char)
7598  */
7599 int
7600 db_monetary_string (const DB_MONETARY * the_monetary, const char *monetary_format, char *string, int max_size)
7601 {
7602  MONETARY_FORMAT mfmt;
7603  int r;
7604 
7605  assert (string != NULL);
7606  assert (max_size > 0);
7607 
7609  if (r != NO_ERROR)
7610  {
7611  return r;
7612  }
7613 
7614  assert (cnv_valid_currency (the_monetary->type));
7615 
7616  mfmt_new (&mfmt, monetary_format, the_monetary->type);
7617  r = mfmt_print (&mfmt, the_monetary->amount, string, max_size);
7618 
7620 
7621  return r;
7622 }
7623 #endif
7624 
7625 /*
7626  * db_string_short() - Change the short value to the result of converting
7627  * the short string in the given format. Return a pointer to the first
7628  * char of the string after the last value char. If an error occurs,
7629  * then the value is unchanged and NULL is returned.
7630  * return:
7631  * error code :
7632  * CNV_ERR_BAD_PATTERN Value string not in expected format
7633  * CNV_ERR_MISSING_INTEGER Not enough digits
7634  * CNV_ERR_INTEGER_OVER_FLOW Value too large
7635  * CNV_ERR_INTEGER_UNDER_FLOW Value too small
7636  * short_string(in) :
7637  * short_format(in) :
7638  * the_short(out) :
7639  */
7640 const char *
7641 db_string_short (const char *short_string, const char *short_format, short *the_short)
7642 {
7643  INTEGER_FORMAT ifmt;
7644  const char *endp;
7645  int the_integer;
7646 
7647  assert (the_short != NULL);
7648  assert (short_string != NULL);
7649 
7650  ifmt_new (&ifmt, short_format);
7651  endp = ifmt_value (&ifmt, short_string, &the_integer);
7652 
7653  if (endp)
7654  {
7655  if (the_integer > DB_INT16_MAX)
7656  {
7658  endp = NULL;
7659  }
7660  else if (the_integer < DB_INT16_MIN)
7661  {
7663  endp = NULL;
7664  }
7665  else
7666  {
7667  *the_short = (short) the_integer;
7668  }
7669  }
7670 
7671  return endp;
7672 }
7673 
7674 #if defined (ENABLE_UNUSED_FUNCTION)
7675 /*
7676  * db_short_string() - Change the given string to a representation of the given
7677  * short value in the given format. If an error occurs, then the contents of
7678  * the string are undefined and an error condition is returned.
7679  * if max_size is not long enough to contain the new float string, then an
7680  * error is returned.
7681  * return:
7682  * the_short(in) :
7683  * short_format(in) :
7684  * string(out) :
7685  * max_size(in) : the maximum number of chars that can be stored in
7686  * the string (including final '\0' char)
7687  */
7688 int
7689 db_short_string (short the_short, const char *short_format, char *string, int max_size)
7690 {
7691  INTEGER_FORMAT ifmt;
7692  int r;
7693 
7694  assert (string != NULL);
7695  assert (max_size > 0);
7696 
7698  if (r != NO_ERROR)
7699  {
7700  return r;
7701  }
7702 
7703  ifmt_new (&ifmt, short_format);
7704  r = ifmt_print (&ifmt, the_short, string, max_size);
7705 
7707 
7708  return r;
7709 }
7710 #endif
7711 
7712 /*
7713  * db_string_time() - Change the time value to the result of converting
7714  * the time string in the given format. Return a pointer to the first
7715  * char of the string after the last value char. If an error occurs,
7716  * then the value is unchanged and NULL is returned.
7717  * return:
7718  * error code:
7719  * CNV_ERR_BAD_PATTERN Value string not in expected format
7720  * CNV_ERR_BAD_TIME Missing or invalid time
7721  * CNV_ERR_BAD_HOUR Missing or invalid hour
7722  * CNV_ERR_BAD_MIN Missing or invalid minute
7723  * CNV_ERR_BAD_SEC Missing or invalid second
7724  * CNV_ERR_BAD_AM_PM Missing or invalid AM/PM
7725  * time_string(in) :
7726  * time_format(in) :
7727  * the_time(out) :
7728  */
7729 const char *
7730 db_string_time (const char *time_string, const char *time_format, DB_TIME * the_time)
7731 {
7732  const FMT_TOKEN *fmt_token;
7733  int hour;
7734  int min;
7735  int sec;
7736  bool pm = false;
7737  bool new_hour = false;
7738  int hrs = 24;
7739  int error = 0;
7740 #if defined (ENABLE_UNUSED_FUNCTION)
7741  const char *value_string;
7742  int i;
7743 #endif
7744 
7745  assert (the_time != NULL);
7746  assert (time_string != NULL);
7747 
7748  /* Initialize to given time. */
7749  db_time_decode (the_time, &hour, &min, &sec);
7750 
7751  /* Scan value string according to format. */
7752  for (fmt_token = tfmt_new (strlen (time_format) ? time_format : "%X"), cnv_fmt_analyze (time_string, FL_LOCAL_TIME);
7753  !error && fmt_token->type != FT_NONE; fmt_token++)
7754  {
7755  switch (fmt_token->type)
7756  {
7757  case FT_TIME:
7758  error = fmt_time_value (fmt_token->text, &hour, &min, &sec);
7759  if (!error)
7760  {
7761  new_hour = true;
7762  }
7763  break;
7764 
7765 #if defined (ENABLE_UNUSED_FUNCTION)
7766  case FT_PATTERN:
7767  /* Pattern string found in value string? */
7768  value_string = cnv_fmt_next_token ();
7769  if (!strncmp (fmt_token->text, value_string, fmt_token->length))
7770  {
7771  /* Yes, restart scan after pattern. */
7772  cnv_fmt_analyze (value_string + fmt_token->length, FL_LOCAL_TIME);
7773  }
7774  else
7775  {
7776  /* No, signal error showing where mismatch occurs. */
7777  for (i = fmt_token->length - 1; i > 0 && strncmp (fmt_token->text, value_string, i); i--);
7778  error = CNV_ERR_BAD_PATTERN;
7779  co_signal (error, CNV_ER_FMT_BAD_PATTERN, fmt_token->text + i, value_string - time_string + i);
7780  }
7781  break;
7782 
7783  case FT_SECOND:
7784  error = fmt_second_value (fmt_token->text, &sec);
7785  break;
7786 
7787  case FT_HOUR:
7788  error = fmt_hour_value (fmt_token->text, &hour);
7789  if (!error)
7790  {
7791  new_hour = true;
7792  }
7793  break;
7794 
7795  case FT_MINUTE:
7796  error = fmt_minute_value (fmt_token->text, &min);
7797  break;
7798 
7799  case FT_ZONE:
7800  /* Not currently supported -- ignore this */
7801  break;
7802 
7803  case FT_AM_PM:
7804  error = local_am_pm_value (&pm);
7805  if (!error)
7806  {
7807  hrs = 12;
7808  }
7809  break;
7810 #endif
7811  default:
7812  assert (!"possible to get here");
7813  }
7814  }
7815 
7816  if (!error)
7817  {
7818  /* Hour consistent with AM/PM? */
7819  if (hrs == 12 && new_hour && (hour > 12 || hour < 1))
7820  {
7821  error = CNV_ERR_BAD_HOUR;
7822  co_signal (error, CNV_ER_FMT_BAD_HOUR, "p");
7823  }
7824  else
7825  {
7826  db_time_encode (the_time, hrs == 12 && pm ? hour % 12 + 12 : hour, min, sec);
7827  }
7828  }
7829 
7830  return error ? NULL : cnv_fmt_next_token ();
7831 }
7832 
7833 /*
7834  * db_time_string() - Change the given string to a representation of the given
7835  * time value in the given format. If an error occurs, then the contents of
7836  * the string are undefined and an error condition is returned.
7837  * if max_size is not long enough to contain the new float string, then an
7838  * error is returned.
7839  * return:
7840  * the_time(in) :
7841  * time_format(in) :
7842  * string(out) :
7843  * max_size(in) : the maximum number of chars that can be stored in
7844  * the string (including final '\0' char)
7845  */
7846 int
7847 db_time_string (const DB_TIME * the_time, const char *time_format, char *string, int max_size)
7848 {
7849  int error = 0;
7850  ADJ_ARRAY *buffer = cnv_get_value_string_buffer (0);
7851  FMT_TOKEN_TYPE ttype;
7852  FMT_TOKEN token;
7853  const char *value_string;
7854 
7855  assert (the_time != NULL);
7856  assert (string != NULL);
7857  assert (max_size > 0);
7858 
7860  if (error != NO_ERROR)
7861  {
7862  return error;
7863  }
7864 
7865  /* Print according to format. */
7866  for (cnv_fmt_analyze (strlen (time_format) ? time_format : "%X", FL_TIME_FORMAT);
7867  (ttype = cnv_fmt_lex (&token)) != FT_NONE; adj_ar_append (buffer, value_string, strlen (value_string)))
7868  {
7869 
7870  switch (ttype)
7871  {
7872  case FT_TIME:
7873  value_string = fmt_time_string (the_time, token.text);
7874  break;
7875 
7876 #if defined (ENABLE_UNUSED_FUNCTION)
7877  case FT_PATTERN:
7878  value_string = token.text;
7879  break;
7880 
7881  case FT_SECOND:
7882  value_string = fmt_second_string (the_time, token.text);
7883  break;
7884 
7885  case FT_HOUR:
7886  value_string = fmt_hour_string (the_time, token.text);
7887  break;
7888 
7889  case FT_MINUTE:
7890  value_string = fmt_minute_string (the_time, token.text);
7891  break;
7892 
7893  case FT_ZONE:
7894  /* Not currently supported -- ignore this */
7895  value_string = "";
7896  break;
7897 
7898  case FT_AM_PM:
7899  value_string = local_am_pm_string (the_time);
7900  break;
7901 #endif
7902  default:
7903  assert (!"possible to get here");
7904  value_string = "";
7905  break;
7906  }
7907  }
7908 
7910 
7911  adj_ar_append (buffer, "", 1);
7912 
7913  /* Enough room to copy completed value string? */
7914  if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
7915  {
7916  error = CNV_ERR_STRING_TOO_LONG;
7917  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
7918  }
7919  else
7920  {
7921  strcpy (string, (char *) adj_ar_get_buffer (buffer));
7922  }
7923 
7924  return error;
7925 }
7926 
7927 /*
7928  * db_string_timestamp() - Change the timestamp value to the result of
7929  * converting the timestamp string in the given format. Return a pointer
7930  * to the first char of the string after the last value char. If an error
7931  * occurs, then the value is unchanged and NULL is returned.
7932  * return:
7933  * error code:
7934  * CNV_ERR_BAD_PATTERN Value string not in expected format
7935  * CNV_ERR_BAD_TIME Missing or invalid time
7936  * CNV_ERR_BAD_HOUR Missing or invalid hour
7937  * CNV_ERR_BAD_MIN Missing or invalid minute
7938  * CNV_ERR_BAD_SEC Missing or invalid second
7939  * CNV_ERR_BAD_AM_PM Missing or invalid AM/PM
7940  * CNV_ERR_BAD_DATE Missing or invalid date
7941  * CNV_ERR_BAD_YEAR Missing or invalid year
7942  * CNV_ERR_BAD_MONTH Missing or invalid month
7943  * CNV_ERR_BAD_MDAY Missing or invalid month day
7944  * CNV_ERR_BAD_WDAY Missing or invalid week day
7945  * timestamp_string(in) :
7946  * timestamp_format(in) :
7947  * the_timestamp(out) :
7948  */
7949 const char *
7950 db_string_timestamp (const char *timestamp_string, const char *timestamp_format, DB_TIMESTAMP * the_timestamp)
7951 {
7952  const FMT_TOKEN *fmt_token;
7953  DB_DATE the_date;
7954  int month;
7955  int day;
7956  int year;
7957  DB_TIME the_time;
7958  int hour;
7959  int min;
7960  int sec;
7961  bool pm = false;
7962  bool new_hour = false;
7963  int hrs = 24;
7964  int error = 0;
7965 #if defined (ENABLE_UNUSED_FUNCTION)
7966  int wday;
7967  const char *value_string;
7968  int i;
7969 #endif
7970 
7971  assert (the_timestamp != NULL);
7972  assert (timestamp_string != NULL);
7973 
7974  /* Initialize to given timestamp. */
7975  (void) db_timestamp_decode_ses (the_timestamp, &the_date, &the_time);
7976  db_date_decode (&the_date, &month, &day, &year);
7977  db_time_decode (&the_time, &hour, &min, &sec);
7978 
7979  /* Scan value string according to format. */
7980  for (fmt_token =
7981  tfmt_new (strlen (timestamp_format) ? timestamp_format : "%c"), cnv_fmt_analyze (timestamp_string,
7982  FL_LOCAL_TIME);
7983  !error && fmt_token->type != FT_NONE; fmt_token++)
7984  {
7985 
7986  switch (fmt_token->type)
7987  {
7988  case FT_TIMESTAMP:
7989  error = fmt_timestamp_value (fmt_token->text, &month, &day, &year, &hour, &min, &sec);
7990  if (!error)
7991  {
7992  new_hour = true;
7993  }
7994  break;
7995 
7996 #if defined (ENABLE_UNUSED_FUNCTION)
7997  case FT_PATTERN:
7998  /* Pattern string found in value string? */
7999  value_string = cnv_fmt_next_token ();
8000  if (!strncmp (fmt_token->text, value_string, fmt_token->length))
8001  {
8002 
8003  /* Yes, restart scan after pattern. */
8004  cnv_fmt_analyze (value_string + fmt_token->length, FL_LOCAL_TIME);
8005  }
8006  else
8007  {
8008  /* No, signal error showing where mismatch occurs. */
8009  for (i = fmt_token->length - 1; i > 0 && strncmp (fmt_token->text, value_string, i); i--)
8010  ;
8011  error = CNV_ERR_BAD_PATTERN;
8012  co_signal (error, CNV_ER_FMT_BAD_PATTERN, fmt_token->text + i, value_string - timestamp_string + i);
8013  }
8014  break;
8015 
8016  case FT_DATE:
8017  error = fmt_date_value (fmt_token->text, &month, &day, &year);
8018  break;
8019 
8020  case FT_YEAR:
8021  error = fmt_year_value (fmt_token->text, &year);
8022  break;
8023 
8024  case FT_MONTH:
8025  error = fmt_month_value (fmt_token->text, &month);
8026  break;
8027 
8028  case FT_MONTHDAY:
8029  error = fmt_monthday_value (fmt_token->text, &day);
8030  break;
8031 
8032  case FT_WEEKDAY:
8033  error = fmt_weekday_value (fmt_token->text, &wday);
8034  if (!error)
8035  {
8036  DB_DATE new_date = fmt_weekday_date (month, day, year, wday);
8037  db_date_decode (&new_date, &month, &day, &year);
8038  }
8039  break;
8040 
8041  case FT_TIME:
8042  error = fmt_time_value (fmt_token->text, &hour, &min, &sec);
8043  if (!error)
8044  {
8045  new_hour = true;
8046  }
8047  break;
8048 
8049  case FT_SECOND:
8050  error = fmt_second_value (fmt_token->text, &sec);
8051  break;
8052 
8053  case FT_HOUR:
8054  error = fmt_hour_value (fmt_token->text, &hour);
8055  if (!error)
8056  {
8057  new_hour = true;
8058  }
8059  break;
8060 
8061  case FT_MINUTE:
8062  error = fmt_minute_value (fmt_token->text, &min);
8063  break;
8064 
8065  case FT_ZONE:
8066  /* Not currently supported */
8067  break;
8068 
8069  case FT_AM_PM:
8070  error = local_am_pm_value (&pm);
8071  if (!error)
8072  {
8073  hrs = 12;
8074  }
8075  break;
8076 #endif
8077  default:
8078  assert (!"possible to get here");
8079  }
8080  }
8081 
8082  if (!error)
8083  {
8084  int m, d, y;
8085 
8086  error = db_date_encode (&the_date, month, day, year);
8087  if (error != NO_ERROR)
8088  {
8089  error = CNV_ERR_UNKNOWN_DATE;
8090  co_signal (error, CNV_ER_FMT_UNKNOWN_DATE, local_date_string (month, day, year));
8091  goto function_end;
8092  }
8093  error = db_time_encode (&the_time, (hrs == 12 && pm ? hour % 12 + 12 : hour), min, sec);
8094  if (error != NO_ERROR)
8095  {
8096  error = CNV_ERR_UNKNOWN_DATE;
8097  co_signal (error, CNV_ER_FMT_UNKNOWN_DATE, local_date_string (month, day, year));
8098  goto function_end;
8099  }
8100 
8101  /* Is this a bogus date like 9/31? */
8102  db_date_decode (&the_date, &m, &d, &y);
8103  if (!(month == m && day == d && year == y))
8104  {
8105  error = CNV_ERR_UNKNOWN_DATE;
8106  co_signal (error, CNV_ER_FMT_UNKNOWN_DATE, local_date_string (month, day, year));
8107  }
8108  /* Hour consistent with AM/PM? */
8109  else if (hrs == 12 && new_hour && (hour > 12 || hour < 1))
8110  {
8111  error = CNV_ERR_BAD_HOUR;
8112  co_signal (error, CNV_ER_FMT_BAD_HOUR, fmt_token->text);
8113  }
8114  else
8115  {
8116  (void) db_timestamp_encode_ses (&the_date, &the_time, the_timestamp, NULL);
8117  }
8118  }
8119 
8120 function_end:
8121  return (error ? NULL : cnv_fmt_next_token ());
8122 }
8123 
8124 /*
8125  * db_timestamp_string() - Change the given string to a representation of
8126  * the given timestamp value in the given format. If an error occurs,
8127  * then the contents of the string are undefined and an error condition
8128  * is returned. if max_size is not long enough to contain the new float
8129  * string, then an error is returned.
8130  * return:
8131  * the_timestamp(in) :
8132  * timestamp_format(in) :
8133  * string(out) :
8134  * max_size(in) : the maximum number of chars that can be stored in
8135  * the string (including final '\0' char)
8136  */
8137 int
8138 db_timestamp_string (const DB_TIMESTAMP * the_timestamp, const char *timestamp_format, char *string, int max_size)
8139 {
8140  int error = 0;
8141  ADJ_ARRAY *buffer = cnv_get_value_string_buffer (0);
8142  FMT_TOKEN_TYPE ttype;
8143  FMT_TOKEN token;
8144  const char *value_string;
8145  DB_DATE the_date;
8146  DB_TIME the_time;
8147  int month, day, year;
8148  int hour, minute, second;
8149 #if defined (ENABLE_UNUSED_FUNCTION)
8150  int weekday;
8151 #endif
8152 
8153  assert (the_timestamp != NULL);
8154  assert (string != NULL);
8155  assert (max_size > 0);
8156 
8158  if (error != NO_ERROR)
8159  {
8160  return error;
8161  }
8162 
8163  /* Reject timestamp encoding errors. */
8164  (void) db_timestamp_decode_ses ((DB_TIMESTAMP *) the_timestamp, &the_date, &the_time);
8165  db_date_decode (&the_date, &month, &day, &year);
8166  db_time_decode (&the_time, &hour, &minute, &second);
8167 
8168  /* Print according to format. */
8169  for (cnv_fmt_analyze (strlen (timestamp_format) ? timestamp_format : "%c", FL_TIME_FORMAT);
8170  (ttype = cnv_fmt_lex (&token)) != FT_NONE; adj_ar_append (buffer, value_string, strlen (value_string)))
8171  {
8172 
8173  switch (ttype)
8174  {
8175  case FT_TIMESTAMP:
8176  value_string = fmt_timestamp_string (the_timestamp, token.text);
8177  break;
8178 
8179 #if defined (ENABLE_UNUSED_FUNCTION)
8180  case FT_PATTERN:
8181  value_string = token.text;
8182  break;
8183 
8184  case FT_DATE:
8185  value_string = fmt_date_string (&the_date, token.text);
8186  break;
8187 
8188  case FT_YEAR:
8189  value_string = fmt_year_string (year, token.text);
8190  break;
8191  case FT_MONTH:
8192  value_string = fmt_month_string (month, token.text);
8193  break;
8194 
8195  case FT_MONTHDAY:
8196  value_string = fmt_monthday_string (day, token.text);
8197  break;
8198  case FT_WEEKDAY:
8199  weekday = db_date_weekday ((DB_DATE *) (&the_date));
8200  value_string = fmt_weekday_string (weekday, token.text);
8201  break;
8202 
8203  case FT_TIME:
8204  value_string = fmt_time_string (&the_time, token.text);
8205  break;
8206 
8207  case FT_SECOND:
8208  value_string = fmt_second_string (&the_time, token.text);
8209  break;
8210 
8211  case FT_HOUR:
8212  value_string = fmt_hour_string (&the_time, token.text);
8213  break;
8214 
8215  case FT_MINUTE:
8216  value_string = fmt_minute_string (&the_time, token.text);
8217  break;
8218 
8219  case FT_ZONE:
8220  /* Not currently supported -- ignore this */
8221  value_string = "";
8222  break;
8223 
8224  case FT_AM_PM:
8225  value_string = local_am_pm_string (&the_time);
8226  break;
8227 #endif
8228  default:
8229  assert (!"possible to get here");
8230  value_string = "";
8231  break;
8232  }
8233  }
8234 
8236 
8237  adj_ar_append (buffer, "", 1);
8238 
8239  /* Enough room to copy completed value string? */
8240  if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
8241  {
8242  error = CNV_ERR_STRING_TOO_LONG;
8243  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
8244  }
8245  else
8246  {
8247  strcpy (string, (char *) adj_ar_get_buffer (buffer));
8248  }
8249 
8250  return error;
8251 }
8252 
8253 /*
8254  * db_string_datetime() -
8255  * return:
8256  * error code:
8257  * CNV_ERR_BAD_PATTERN Value string not in expected format
8258  * CNV_ERR_BAD_TIME Missing or invalid time
8259  * CNV_ERR_BAD_HOUR Missing or invalid hour
8260  * CNV_ERR_BAD_MIN Missing or invalid minute
8261  * CNV_ERR_BAD_SEC Missing or invalid second
8262  * CNV_ERR_BAD_AM_PM Missing or invalid AM/PM
8263  * CNV_ERR_BAD_DATE Missing or invalid date
8264  * CNV_ERR_BAD_YEAR Missing or invalid year
8265  * CNV_ERR_BAD_MONTH Missing or invalid month
8266  * CNV_ERR_BAD_MDAY Missing or invalid month day
8267  * CNV_ERR_BAD_WDAY Missing or invalid week day
8268  * timestamp_string(in) :
8269  * timestamp_format(in) :
8270  * the_timestamp(out) :
8271  */
8272 const char *
8273 db_string_datetime (const char *datetime_string, const char *datetime_format, DB_DATETIME * the_datetime)
8274 {
8275  const FMT_TOKEN *fmt_token;
8276  DB_DATETIME tmp_datetime;
8277  int month;
8278  int day;
8279  int year;
8280  int hour;
8281  int min;
8282  int sec;
8283  int msec;
8284  bool pm = false;
8285  bool new_hour = false;
8286  int hrs = 24;
8287  int error = 0;
8288 #if defined (ENABLE_UNUSED_FUNCTION)
8289  int wday;
8290  const char *value_string;
8291  int i;
8292 #endif
8293 
8294  assert (the_datetime != NULL);
8295  assert (datetime_string != NULL);
8296 
8297  /* Initialize to given datetime. */
8298  db_datetime_decode (the_datetime, &month, &day, &year, &hour, &min, &sec, &msec);
8299 
8300  /* Scan value string according to format. */
8301  for (fmt_token =
8302  tfmt_new (strlen (datetime_format) ? datetime_format : "%c"), cnv_fmt_analyze (datetime_string, FL_LOCAL_TIME);
8303  !error && fmt_token->type != FT_NONE; fmt_token++)
8304  {
8305  switch (fmt_token->type)
8306  {
8307  case FT_TIMESTAMP:
8308  error = fmt_timestamp_value (fmt_token->text, &month, &day, &year, &hour, &min, &sec);
8309  if (!error)
8310  {
8311  new_hour = true;
8312  }
8313  break;
8314 
8315 #if defined (ENABLE_UNUSED_FUNCTION)
8316  case FT_PATTERN:
8317  /* Pattern string found in value string? */
8318  value_string = cnv_fmt_next_token ();
8319  if (!strncmp (fmt_token->text, value_string, fmt_token->length))
8320  {
8321 
8322  /* Yes, restart scan after pattern. */
8323  cnv_fmt_analyze (value_string + fmt_token->length, FL_LOCAL_TIME);
8324  }
8325  else
8326  {
8327  /* No, signal error showing where mismatch occurs. */
8328  for (i = fmt_token->length - 1; i > 0 && strncmp (fmt_token->text, value_string, i); i--);
8329  error = CNV_ERR_BAD_PATTERN;
8330  co_signal (error, CNV_ER_FMT_BAD_PATTERN, fmt_token->text + i, value_string - datetime_string + i);
8331  }
8332  break;
8333  case FT_DATE:
8334  error = fmt_date_value (fmt_token->text, &month, &day, &year);
8335  break;
8336  case FT_YEAR:
8337  error = fmt_year_value (fmt_token->text, &year);
8338  break;
8339  case FT_MONTH:
8340  error = fmt_month_value (fmt_token->text, &month);
8341  break;
8342  case FT_MONTHDAY:
8343  error = fmt_monthday_value (fmt_token->text, &day);
8344  break;
8345  case FT_WEEKDAY:
8346  error = fmt_weekday_value (fmt_token->text, &wday);
8347  if (!error)
8348  {
8349  DB_DATE new_date = fmt_weekday_date (month, day, year, wday);
8350  db_date_decode (&new_date, &month, &day, &year);
8351  }
8352  break;
8353  case FT_TIME:
8354  error = fmt_time_value (fmt_token->text, &hour, &min, &sec);
8355  if (!error)
8356  {
8357  new_hour = true;
8358  }
8359  break;
8360  case FT_SECOND:
8361  error = fmt_second_value (fmt_token->text, &sec);
8362  break;
8363  case FT_HOUR:
8364  error = fmt_hour_value (fmt_token->text, &hour);
8365  if (!error)
8366  {
8367  new_hour = true;
8368  }
8369  break;
8370  case FT_MINUTE:
8371  error = fmt_minute_value (fmt_token->text, &min);
8372  break;
8373  case FT_ZONE:
8374  /* Not currently supported */
8375  break;
8376  case FT_AM_PM:
8377  error = local_am_pm_value (&pm);
8378  if (!error)
8379  {
8380  hrs = 12;
8381  }
8382  break;
8383 #endif
8384  default:
8385  assert (!"possible to get here");
8386  }
8387  }
8388 
8389  if (!error)
8390  {
8391  int m, d, y, hh, mm, ss, ms;
8392  db_datetime_encode (&tmp_datetime, month, day, year, (hrs == 12 && pm ? hour % 12 + 12 : hour), min, sec, msec);
8393  /* Is this a bogus date like 9/31? */
8394  db_datetime_decode (&tmp_datetime, &m, &d, &y, &hh, &mm, &ss, &ms);
8395  if (!(month == m && day == d && year == y))
8396  {
8397  error = CNV_ERR_UNKNOWN_DATE;
8398  co_signal (error, CNV_ER_FMT_UNKNOWN_DATE, local_date_string (month, day, year));
8399  }
8400  /* Hour consistent with AM/PM? */
8401  else if (hrs == 12 && new_hour && (hour > 12 || hour < 1))
8402  {
8403  error = CNV_ERR_BAD_HOUR;
8404  co_signal (error, CNV_ER_FMT_BAD_HOUR, fmt_token->text);
8405  }
8406  else
8407  {
8408  *the_datetime = tmp_datetime;
8409  }
8410  }
8411 
8412  return (error ? NULL : cnv_fmt_next_token ());
8413 }
8414 
8415 /*
8416  * db_datetime_string() -
8417  * return:
8418  * the_datetime(in) :
8419  * datetime_format(in) :
8420  * string(out) :
8421  * max_size(in) : the maximum number of chars that can be stored in
8422  * the string (including final '\0' char)
8423  */
8424 int
8425 db_datetime_string (const DB_DATETIME * the_datetime, const char *datetime_format, char *string, int max_size)
8426 {
8427  int error = 0;
8428  ADJ_ARRAY *buffer = cnv_get_value_string_buffer (0);
8429  FMT_TOKEN_TYPE ttype;
8430  FMT_TOKEN token;
8431  const char *value_string;
8432  DB_DATE the_date;
8433  DB_TIMESTAMP the_timestamp;
8434  int month, day, year;
8435  int hour, minute, second, millisecond;
8436 #if defined (ENABLE_UNUSED_FUNCTION)
8437  int weekday;
8438 #endif
8439  unsigned int the_time;
8440 
8441  assert (the_datetime != NULL);
8442  assert (string != NULL);
8443  assert (max_size > 0);
8444 
8446  if (error != NO_ERROR)
8447  {
8448  return error;
8449  }
8450 
8451  /* Reject datetime encoding errors. */
8452  db_datetime_decode ((DB_DATETIME *) the_datetime, &month, &day, &year, &hour, &minute, &second, &millisecond);
8453 
8454  /* Print according to format. */
8455  for (cnv_fmt_analyze ((strlen (datetime_format) ? datetime_format : "%c"), FL_TIME_FORMAT);
8456  (ttype = cnv_fmt_lex (&token)) != FT_NONE; adj_ar_append (buffer, value_string, strlen (value_string)))
8457  {
8458  switch (ttype)
8459  {
8460  case FT_TIMESTAMP:
8461  db_date_encode (&the_date, month, day, year);
8462  db_time_encode (&the_time, hour, minute, second);
8463  (void) db_timestamp_encode_ses (&the_date, &the_time, &the_timestamp, NULL);
8464 
8465  value_string = fmt_timestamp_string (&the_timestamp, token.text);
8466  break;
8467 #if defined (ENABLE_UNUSED_FUNCTION)
8468  case FT_PATTERN:
8469  value_string = token.text;
8470  break;
8471  case FT_DATE:
8472  db_date_encode (&the_date, month, day, year);
8473  value_string = fmt_date_string (&the_date, token.text);
8474  break;
8475  case FT_YEAR:
8476  value_string = fmt_year_string (year, token.text);
8477  break;
8478  case FT_MONTH:
8479  value_string = fmt_month_string (month, token.text);
8480  break;
8481  case FT_MONTHDAY:
8482  value_string = fmt_monthday_string (day, token.text);
8483  break;
8484  case FT_WEEKDAY:
8485  db_date_encode (&the_date, month, day, year);
8486  weekday = db_date_weekday ((DB_DATE *) (&the_date));
8487  value_string = fmt_weekday_string (weekday, token.text);
8488  break;
8489  case FT_TIME:
8490  db_time_encode (&the_time, hour, minute, second);
8491  value_string = fmt_time_string (&the_time, token.text);
8492  break;
8493  case FT_SECOND:
8494  db_time_encode (&the_time, hour, minute, second);
8495  value_string = fmt_second_string (&the_time, token.text);
8496  break;
8497  case FT_MILLISECOND:
8498  db_time_encode (&the_time, hour, minute, second);
8499  value_string = fmt_second_string (&the_time, token.text);
8500  break;
8501  case FT_HOUR:
8502  db_time_encode (&the_time, hour, minute, second);
8503  value_string = fmt_hour_string (&the_time, token.text);
8504  break;
8505  case FT_MINUTE:
8506  db_time_encode (&the_time, hour, minute, second);
8507  value_string = fmt_minute_string (&the_time, token.text);
8508  break;
8509  case FT_ZONE:
8510  /* Not currently supported -- ignore this */
8511  value_string = "";
8512  break;
8513  case FT_AM_PM:
8514  db_time_encode (&the_time, hour, minute, second);
8515  value_string = local_am_pm_string (&the_time);
8516  break;
8517 #endif
8518  default:
8519  assert (!"possible to get here");
8520  value_string = "";
8521  break;
8522  }
8523  }
8524 
8526  adj_ar_append (buffer, "", 1);
8527  /* Enough room to copy completed value string? */
8528  if ((int) strlen ((char *) adj_ar_get_buffer (buffer)) >= max_size)
8529  {
8530  error = CNV_ERR_STRING_TOO_LONG;
8531  co_signal (error, CNV_ER_FMT_STRING_TOO_LONG, max_size - 1);
8532  }
8533  else
8534  {
8535  strcpy (string, (char *) adj_ar_get_buffer (buffer));
8536  }
8537 
8538  return error;
8539 }
8540 
8541 /*
8542  * db_string_bit() -
8543  * return:
8544  * bit_char_string(in) :
8545  * bit_format(in) :
8546  * the_db_bit(out) :
8547  */
8548 const char *
8549 db_string_bit (const char *bit_char_string, const char *bit_format, DB_VALUE * the_db_bit)
8550 {
8551  BIT_STRING_FORMAT bfmt;
8552 
8553  assert (bit_char_string != NULL);
8554  assert (the_db_bit != NULL);
8555 
8556  bfmt_new (&bfmt, bit_format);
8557  return bfmt_value (bfmt, bit_char_string, the_db_bit);
8558 }
8559 
8560 /*
8561  * db_bit_string() - Change the given string to a representation of
8562  * the given bit value in the given format. If an error occurs, then
8563  * the contents of the string are undefined and an error condition is
8564  * returned.
8565  * if max_size is not long enough to contain the new float string, then an
8566  * error is returned.
8567  * return:
8568  * the_db_bit(in) :
8569  * bit_format(in) :
8570  * string(out) :
8571  * max_size(in) : the maximum number of chars that can be stored in
8572  * the string (including final '\0' char)
8573  */
8574 int
8575 db_bit_string (const DB_VALUE * the_db_bit, const char *bit_format, char *string, int max_size)
8576 {
8577  BIT_STRING_FORMAT bfmt;
8578  int r;
8579 
8580  assert (string != NULL);
8581  assert (max_size > 0);
8582 
8584  if (r != NO_ERROR)
8585  {
8586  return r;
8587  }
8588 
8589  bfmt_new (&bfmt, bit_format);
8590  r = bfmt_print (&bfmt, the_db_bit, string, max_size);
8591 
8593 
8594  return r;
8595 }
8596 
8597 #if defined (ENABLE_UNUSED_FUNCTION)
8598 /*
8599  * db_validate_format() - If the given format string is valid for the given
8600  * data type, then return 0. otherwise, signal and return an error condition.
8601  * return:
8602  * format(in) :
8603  * type(in) :
8604  */
8605 int
8606 db_validate_format (const char *format, DB_TYPE type)
8607 {
8608  int error = 0;
8609 
8610  assert (type == DB_TYPE_STRING || type == DB_TYPE_NULL || format != NULL);
8611 
8612  switch (type)
8613  {
8614  case DB_TYPE_DATE:
8615  error = fmt_validate (format, FL_VALIDATE_DATE_FORMAT, FT_DATE_FORMAT, DB_TYPE_DATE);
8616  break;
8617 
8618  case DB_TYPE_DOUBLE:
8619  case DB_TYPE_FLOAT:
8620  case DB_TYPE_NUMERIC:
8621  error = fmt_validate (format, FL_VALIDATE_FLOAT_FORMAT, FT_FLOAT_FORMAT, DB_TYPE_FLOAT);
8622  break;
8623 
8624  case DB_TYPE_BIGINT:
8625  case DB_TYPE_INTEGER:
8626  case DB_TYPE_SHORT:
8627  error = fmt_validate (format, FL_VALIDATE_INTEGER_FORMAT, FT_INTEGER_FORMAT, DB_TYPE_INTEGER);
8628  break;
8629 
8630  case DB_TYPE_MONETARY:
8631  error = fmt_validate (format, FL_VALIDATE_MONETARY_FORMAT, FT_MONETARY_FORMAT, DB_TYPE_MONETARY);
8632  break;
8633 
8634  case DB_TYPE_TIME:
8635  error = fmt_validate (format, FL_VALIDATE_TIME_FORMAT, FT_TIME_FORMAT, DB_TYPE_TIME);
8636  break;
8637 
8638  case DB_TYPE_TIMESTAMP:
8639  error = fmt_validate (format, FL_VALIDATE_TIMESTAMP_FORMAT, FT_TIMESTAMP_FORMAT, DB_TYPE_TIMESTAMP);
8640  break;
8641 
8642  /* TODO:DATETIME datetime format ?? */
8643  case DB_TYPE_DATETIME:
8644  error = fmt_validate (format, FL_VALIDATE_TIMESTAMP_FORMAT, FT_TIMESTAMP_FORMAT, DB_TYPE_DATETIME);
8645  break;
8646 
8647  case DB_TYPE_NULL:
8648  case DB_TYPE_CHAR:
8649  case DB_TYPE_VARCHAR:
8650  case DB_TYPE_NCHAR:
8651  case DB_TYPE_VARNCHAR:
8652  break;
8653 
8654  case DB_TYPE_VARBIT:
8655  case DB_TYPE_BIT:
8656  error = fmt_validate (format, FL_VALIDATE_BIT_STRING_FORMAT, FT_BIT_STRING_FORMAT, DB_TYPE_BIT);
8657  break;
8658 
8659  case DB_TYPE_BLOB:
8660  case DB_TYPE_CLOB:
8661  case DB_TYPE_ERROR:
8662  case DB_TYPE_DB_VALUE:
8663  case DB_TYPE_OBJECT:
8664  case DB_TYPE_OID:
8665  case DB_TYPE_POINTER:
8666  case DB_TYPE_SET:
8667  case DB_TYPE_MULTISET:
8668  case DB_TYPE_SEQUENCE:
8669  case DB_TYPE_SUB:
8670  case DB_TYPE_VARIABLE:
8671  case DB_TYPE_VOBJ:
8672  error = CNV_ERR_BAD_TYPE;
8673  co_signal (error, CNV_ER_FMT_BAD_TYPE, pr_type_name (type));
8674  break;
8675 
8676  default:
8677  assert (!"Valid DB_TYPE");
8678  break;
8679  }
8680 
8681  return error;
8682 }
8683 #endif
8684 
8685 /*
8686  * cnv_cleanup() - This function is called when the database connection is shut
8687  * down so that anything we allocated by the cnv_ module and maintained in
8688  * static variables can be reclaimed.
8689  * return:
8690  */
8691 void
8693 {
8694  cnv_fmt_exit ();
8695  cnvutil_cleanup ();
8696 }
8697 
8698 #if defined (SERVER_MODE)
8699 /*
8700  * cnv_get_thread_local_adj_buffer() -
8701  * return:
8702  * idx(in):
8703  */
8704 static ADJ_ARRAY *
8705 cnv_get_thread_local_adj_buffer (int idx)
8706 {
8707  THREAD_ENTRY *thread_p;
8708 
8709  thread_p = thread_get_thread_entry_info ();
8710  assert (thread_p != NULL);
8711 
8712  return thread_p->cnv_adj_buffer[idx];
8713 }
8714 
8715 /*
8716  * cnv_set_thread_local_adj_buffer() -
8717  * return: void
8718  * idx(in):
8719  * buffer_p(in):
8720  */
8721 static void
8722 cnv_set_thread_local_adj_buffer (int idx, ADJ_ARRAY * buffer_p)
8723 {
8724  THREAD_ENTRY *thread_p;
8725 
8726  thread_p = thread_get_thread_entry_info ();
8727  assert (thread_p != NULL);
8728 
8729  thread_p->cnv_adj_buffer[idx] = buffer_p;
8730 }
8731 #endif // SERVER_MODE
bool sign_required
Definition: cnv.c:174
#define CNV_ERR_NO_SIGN
Definition: cnverr.h:36
#define CNV_ERR_BAD_BINARY_DIGIT
Definition: cnv.c:77
#define KOREAN_EUC_DAY_SYMBOL
Definition: cnv.c:134
DB_C_FLOAT db_get_float(const DB_VALUE *value)
const char * db_string_bit(const char *bit_char_string, const char *bit_format, DB_VALUE *the_db_bit)
Definition: cnv.c:8549
#define CNV_ER_FMT_EXTRA_SIGN
Definition: cnverr.h:107
#define CNV_ER_FMT_NO_SIGN
Definition: cnverr.h:85
static const char * local_am_pm_string(const DB_TIME *the_time)
Definition: cnv.c:2162
#define CNV_ER_FMT_INTEGER_UNDERFLOW
Definition: cnverr.h:111
int db_make_datetime(DB_VALUE *value, const DB_DATETIME *datetime)
FMT_LEX_MODE cnv_fmt_number_mode(INTL_ZONE zone)
Definition: cnvlex.c:1928
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
int intl_mbs_len(const char *mbs)
Definition: intl_support.c:183
#define LANG_SYS_COLLATION
const char * db_string_bigint(const char *bitint_string, const char *bigint_format, DB_BIGINT *the_bigint)
Definition: cnv.c:7503
#define CNV_ER_FMT_BAD_MDAY
Definition: cnverr.h:127
static int hex_string_to_int(const char *src, int nhex)
Definition: cnv.c:5795
#define CNV_ERR_BAD_LEADING
Definition: cnverr.h:37
#define CNV_ER_FMT_STRING_TOO_LONG
Definition: cnverr.h:77
Definition: cnvlex.h:67
int db_string_to_timestamp(const char *str, DB_TIMESTAMP *utime)
Definition: db_date.c:3802
static const char * kr_short_month_names[]
Definition: cnv.c:413
#define db_locate_numeric(value)
#define CNV_ER_FMT_TIMESTAMP_OVERFLOW
Definition: cnverr.h:153
#define CNV_ER_FMT_BAD_POSITION
Definition: cnverr.h:103
#define CNV_ER_FMT_BAD_TRAILING
Definition: cnverr.h:89
int integral_digits
Definition: cnv.c:165
FMT_TOKEN_TYPE type
Definition: cnvlex.h:111
static bool bfmt_valid_char(FMT_TOKEN *token)
Definition: cnv.c:5730
int fractional_digits
Definition: cnv.c:167
#define CNV_ERR_BAD_AM_PM
Definition: cnverr.h:67
const char * db_string_short(const char *short_string, const char *short_format, short *the_short)
Definition: cnv.c:7641
static const char * ifmt_numeric_value(INTEGER_FORMAT *ifmt, const char *string, int *the_integer)
Definition: cnv.c:5341
#define CNV_ERR_FLOAT_OVERFLOW
Definition: cnverr.h:59
DB_CONST_C_BIT db_get_bit(const DB_VALUE *value, int *length)
FORMAT_DIGIT integral_type
Definition: cnv.c:166
DB_CONST_C_NCHAR db_get_nchar(const DB_VALUE *value, int *length)
#define CNV_ERR_EXTRA_SIGN
Definition: cnverr.h:47
char * intl_mbs_chr(const char *mbs, wchar_t wc)
Definition: intl_support.c:149
int db_get_int(const DB_VALUE *value)
int db_make_bigint(DB_VALUE *value, const DB_BIGINT num)
static int local_date_value(int *, int *, int *)
Definition: cnv.c:1980
static int cnv_bad_char(const char *string, bool unknown)
Definition: cnv.c:2670
#define CNV_ER_FMT_BAD_MIN
Definition: cnverr.h:141
DB_TYPE
Definition: dbtype_def.h:670
int parse_int(int *ret_p, const char *str_p, int base)
Definition: porting.c:2290
#define KOREAN_EUC_MONTH_SYMBOL
Definition: cnv.c:133
int db_datetime_string(const DB_DATETIME *the_datetime, const char *datetime_format, char *string, int max_size)
Definition: cnv.c:8425
DB_C_DOUBLE db_get_double(const DB_VALUE *value)
const char * adj_ar_concat_strings(const char *string1, const char *string2,...)
#define CNV_ER_FMT_BAD_WDAY
Definition: cnverr.h:129
int db_make_varchar(DB_VALUE *value, const int max_char_length, DB_CONST_C_CHAR str, const int char_str_byte_size, const int codeset, const int collation_id)
static const char * ifmt_value(INTEGER_FORMAT *ifmt, const char *string, int *the_integer)
Definition: cnv.c:5301
int db_datetime_decode(const DB_DATETIME *datetime, int *month, int *day, int *year, int *hour, int *minute, int *second, int *millisecond)
Definition: db_date.c:4574
#define csect_enter(a, b, c)
Definition: cnv.c:138
const char * db_string_timestamp(const char *timestamp_string, const char *timestamp_format, DB_TIMESTAMP *the_timestamp)
Definition: cnv.c:7950
int integral_digits
Definition: cnv.c:176
int db_timestamp_encode_ses(const DB_DATE *date, const DB_TIME *timeval, DB_TIMESTAMP *utime, TZ_ID *dest_tz_id)
Definition: db_date.c:597
const char * db_string_double(const char *double_string, const char *double_format, double *the_double)
Definition: cnv.c:7223
#define LOCAL_COLON
Definition: cnv.c:116
static void mfmt_new(MONETARY_FORMAT *mfmt, const char *format, DB_CURRENCY currency_type)
Definition: cnv.c:4854
static const char * bifmt_numeric_value(INTEGER_FORMAT *ifmt, const char *string, DB_BIGINT *the_bigint)
Definition: cnv.c:5396
bool scientific
Definition: cnv.c:162
#define CNV_ER_FMT_BAD_TIME
Definition: cnverr.h:137
const char * intl_mbs_nth(const char *mbs, size_t n)
Definition: intl_support.c:219
int db_make_numeric(DB_VALUE *value, const DB_C_NUMERIC num, const int precision, const int scale)
FMT_TOKEN_TYPE cnv_fmt_lex(FMT_TOKEN *token)
int db_string_to_datetime(const char *str, DB_DATETIME *datetime)
Definition: db_date.c:4441
#define ADJ_AR_EOA
static const char * local_am(void)
Definition: cnv.c:1725
int co_code(void)
static int fmt_fractional_value(FORMAT_DIGIT type, int ndigits, double *the_value)
Definition: cnv.c:2967
FMT_LEX_MODE
Definition: cnvlex.h:37
int integral_digits
Definition: cnv.c:186
intl_zone
Definition: intl_support.h:143
static const char * bifmt_value(INTEGER_FORMAT *bifmt, const char *string, DB_BIGINT *the_bigint)
Definition: cnv.c:5321
const char * db_string_date(const char *date_string, const char *date_format, DB_DATE *the_date)
Definition: cnv.c:7019
FORMAT_DIGIT integral_type
Definition: cnv.c:187
#define FMT_SCIENTIFIC()
Definition: cnv.c:120
#define CNV_ERR_BAD_POSITION
Definition: cnverr.h:45
int value
Definition: cnvlex.h:115
const char * db_string_time(const char *time_string, const char *time_format, DB_TIME *the_time)
Definition: cnv.c:7730
FORMAT_DIGIT
Definition: cnv.c:144
#define CNV_ER_FMT_BAD_CHAR
Definition: cnverr.h:81
#define CNV_ERR_NO_DECIMAL
Definition: cnverr.h:35
void * adj_ar_get_buffer(const ADJ_ARRAY *adj_array_p)
DB_CONST_C_CHAR db_get_char(const DB_VALUE *value, int *length)
void cnv_fmt_analyze(const char *instring, FMT_LEX_MODE mode)
Definition: cnvlex.c:1869
#define CNV_ERR_BAD_TIMESTAMP
Definition: cnverr.h:68
int co_signal(int code, const char *format,...)
void cnv_cleanup(void)
Definition: cnv.c:8692
#define CAST_STRLEN
Definition: porting.h:470
Definition: cnvlex.h:89
static bool ifmt_valid_char(FMT_TOKEN *token)
Definition: cnv.c:5213
#define LOCAL_EXP_LENGTH
Definition: cnv.c:113
#define LOCAL_SPACE
Definition: cnv.c:111
const char * pattern
Definition: cnv.c:178
#define bool
Definition: dbi_compat.h:31
#define FMT_MAX_TIMESTAMP_STRING
Definition: cnv.c:97
#define CNV_ER_FMT_UNKNOWN_DATE
Definition: cnverr.h:135
#define CNV_ERR_BAD_CHAR
Definition: cnverr.h:34
#define CNV_ER_FMT_BAD_TYPE
Definition: cnverr.h:79
static const char * us_date_string(int month, int day, int year)
Definition: cnv.c:502
bool thousands
Definition: cnv.c:184
static const char * local_grouping(void)
Definition: cnv.c:1687
#define FMT_MAX_DATE_STRING
Definition: cnv.c:88
int intl_mbs_spn(const char *mbs, const wchar_t *chars)
Definition: intl_support.c:269
static const char * us_time_string(const DB_TIME *the_time)
Definition: cnv.c:643
#define FMT_MAX_TIME_STRING
Definition: cnv.c:91
static int fmt_max_digits
Definition: cnv.c:373
#define DB_VALUE_SCALE(value)
Definition: dbtype.h:74
int db_date_weekday(DB_DATE *date)
Definition: db_date.c:321
#define DEC_BUFFER_SIZE
Definition: cnv.c:72
void THREAD_ENTRY
static int fmt_time_value(const char *descriptor, int *the_hour, int *the_min, int *the_sec)
Definition: cnv.c:3926
#define CNV_ERR_MISSING_INTEGER
Definition: cnverr.h:42
int db_date_encode(DB_DATE *date, int month, int day, int year)
Definition: db_date.c:275
int db_make_short(DB_VALUE *value, const DB_C_SHORT num)
#define BYTE_COUNT(bit_cnt)
Definition: cnv.c:74
int adj_ar_length(const ADJ_ARRAY *adj_array_p)
#define CNV_ERR_BAD_NULL
Definition: cnverr.h:46
static int us_date_value(int *the_month, int *the_day, int *the_year)
Definition: cnv.c:522
#define CNV_ERR_BAD_FORMAT
Definition: cnverr.h:74
bool thousands
Definition: cnv.c:163
DB_MONETARY * db_get_monetary(const DB_VALUE *value)
const char * db_string_integer(const char *integer_string, const char *integer_format, int *the_integer)
Definition: cnv.c:7443
int db_string_to_time(const char *str, DB_TIME *time)
Definition: db_date.c:3739
static void ifmt_new(INTEGER_FORMAT *ifmt, const char *format)
Definition: cnv.c:5228
DB_CURRENCY
Definition: dbtype_def.h:799
#define CNV_ER_FMT_EXTRA_FRACTION
Definition: cnverr.h:95
static int num_fmt_print(FLOAT_FORMAT *ffmt, const DB_VALUE *the_numeric, char *string, int max_size)
Definition: cnv.c:6393
#define CNV_ER_FMT_FLOAT_UNDERFLOW
Definition: cnverr.h:133
int fractional_digits
Definition: cnv.c:188
#define CNV_ERR_BAD_YEAR
Definition: cnverr.h:55
unsigned int DB_TIMESTAMP
Definition: dbtype_def.h:759
static ADJ_ARRAY * cnv_adj_buffer3
Definition: cnv.c:400
bool decimal
Definition: cnv.c:164
static const char * eng_short_weekday_names[]
Definition: cnv.c:473
const char * text
Definition: cnvlex.h:112
#define CNV_ERR_BAD_THOUS
Definition: cnverr.h:39
static INTL_ZONE cnv_currency_zone(DB_CURRENCY currency)
Definition: cnv.c:2394
static const FMT_TOKEN * tfmt_new(const char *format)
Definition: cnv.c:4479
#define CNV_ERR_INTEGER_OVERFLOW
Definition: cnverr.h:48
static int us_time_value(int *the_hour, int *the_min, int *the_sec)
Definition: cnv.c:666
int db_value_put_encoded_time(DB_VALUE *value, const DB_TIME *time)
Definition: db_macro.c:1357
#define CNV_ERR_BAD_SEC
Definition: cnverr.h:65
#define CNV_ER_FMT_EXTRA_INTEGER
Definition: cnverr.h:93
static const char * fmt_timestamp_string(const DB_TIMESTAMP *the_timestamp, const char *descriptor)
Definition: cnv.c:4291
#define DB_INT32_MIN
Definition: dbtype_def.h:632
#define assert(x)
Definition: cnv.c:146
const char * db_string_value(const char *string, int str_size, const char *format, DB_VALUE *value)
Definition: cnv.c:6501
int db_make_monetary(DB_VALUE *value, const DB_CURRENCY type, const double amount)
static bool ffmt_valid_char(FMT_TOKEN *token)
Definition: cnv.c:4533
#define GET_MIN(a, b)
Definition: cnv.c:73
#define LOCAL_0
Definition: cnv.c:112
#define FMT_X()
Definition: cnv.c:125
static int fmt_minute_value(const char *, int *)
Definition: cnv.c:4181
enum bit_string_format_e BIT_STRING_FORMAT
int db_time_string(const DB_TIME *the_time, const char *time_format, char *string, int max_size)
Definition: cnv.c:7847
#define FMT_DECIMAL()
Definition: cnv.c:122
#define CNV_ERR_BAD_HOUR
Definition: cnverr.h:63
static const char * local_date_string(int month, int day, int year)
Definition: cnv.c:1942
#define CNV_ER_FMT_BAD_HOUR
Definition: cnverr.h:139
void cnv_fmt_exit(void)
Definition: cnvlex.c:1995
int db_time_encode(DB_TIME *timeval, int hour, int minute, int second)
Definition: db_date.c:370
static ADJ_ARRAY * cnv_adj_buffer2
Definition: cnv.c:397
bool thousands
Definition: cnv.c:175
#define CNV_ERR_BAD_MONTH
Definition: cnverr.h:56
#define DB_VALUE_DOMAIN_TYPE(value)
Definition: dbtype.h:70
#define CNV_ER_FMT_TIMESTAMP_UNDERFLOW
Definition: cnverr.h:151
static int fmt_fractional_digits(FORMAT_DIGIT type, int ndigits, double *the_value, int *nfound)
Definition: cnv.c:2901
#define DB_INT32_MAX
Definition: dbtype_def.h:633
#define BYTE_COUNT_HEX(bit_cnt)
Definition: cnv.c:75
static const char * mfmt_value(MONETARY_FORMAT *mfmt, const char *string, double *the_double)
Definition: cnv.c:4974
static const char * local_pm(void)
Definition: cnv.c:1760
#define CNV_ER_FMT_BAD_PATTERN
Definition: cnverr.h:113
static enum scanner_mode mode
#define CNV_ER_FMT_BAD_DATE
Definition: cnverr.h:121
#define CNV_ERR_STRING_TOO_LONG
Definition: cnverr.h:32
bool decimal
Definition: cnv.c:185
static bool cnv_valid_currency(DB_CURRENCY currency)
Definition: cnv.c:2499
#define min(a, b)
int db_timestamp_string(const DB_TIMESTAMP *the_timestamp, const char *timestamp_format, char *string, int max_size)
Definition: cnv.c:8138
#define mbs_eql(s1, s2)
Definition: cnv.c:104
static const char * kor_weekday_names[]
Definition: cnv.c:403
#define CNV_ERR_NO_CURRENCY
Definition: cnverr.h:52
Definition: cnv.c:147
#define CNV_ER_FMT_BAD_DATETIME
Definition: cnverr.h:155
static void cnvutil_cleanup(void)
Definition: cnv.c:3386
#define CNV_ERR_MISSING_FRACTION
Definition: cnverr.h:43
Definition: cnvlex.h:61
static int ko_time_value(int *the_hour, int *the_min, int *the_sec)
Definition: cnv.c:1359
#define CNV_ER_FMT_NO_CURRENCY
Definition: cnverr.h:117
DB_CURRENCY currency
Definition: cnv.c:191
const char * cnv_fmt_next_token()
Definition: cnvlex.c:1893
#define NULL
Definition: freelistheap.h:34
#define FMT_MAX_DATETIME_STRING
Definition: cnv.c:101
static const char * eng_short_month_names[]
Definition: cnv.c:443
static const char * ko_date_string(int month, int day, int year)
Definition: cnv.c:1097
int adj_ar_replace(ADJ_ARRAY *adj_array_p, const void *src, int src_length, int start, int end)
const char * pr_type_name(DB_TYPE id)
DB_CURRENCY type
Definition: dbtype_def.h:832
#define WCSCAT(buffer, wcs1, wcs2)
Definition: cnv.c:117
#define db_private_free_and_init(thrd, ptr)
Definition: memory_alloc.h:141
int db_value_put_encoded_date(DB_VALUE *value, const DB_DATE *date)
Definition: db_macro.c:1383
#define FMT_MAX_DIGITS
Definition: cnv.c:82
#define CNV_ERR_BAD_DATETIME
Definition: cnverr.h:71
FMT_LEX_MODE mode
Definition: cnv.c:192
static ADJ_ARRAY * cnv_adj_buffer1
Definition: cnv.c:394
#define CNV_ERR_BAD_WDAY
Definition: cnverr.h:58
static int fmt_integral_value(FORMAT_DIGIT type, int ndigits, bool sign_required, bool thousands, double *the_value)
Definition: cnv.c:2732
#define csect_exit(a, b)
Definition: cnv.c:139
void numeric_coerce_num_to_dec_str(DB_C_NUMERIC num, char *dec_str)
int adj_ar_append(ADJ_ARRAY *adj_array_p, const void *src, int src_length)
#define CNV_ERR_BAD_MDAY
Definition: cnverr.h:57
#define db_private_alloc(thrd, size)
Definition: memory_alloc.h:227
#define MB_LEN_MAX
Definition: intl_support.h:53
#define CNV_ER_FMT_MISSING_INTEGER
Definition: cnverr.h:97
static const char * fmt_date_string(const DB_DATE *the_date, const char *descriptor)
Definition: cnv.c:3433
enum intl_zone INTL_ZONE
Definition: intl_support.h:150
need_clear_type need_clear
Definition: dbtype_def.h:1084
int adj_ar_remove(ADJ_ARRAY *adj_array_p, int start, int end)
static void ffmt_new(FLOAT_FORMAT *ffmt, const char *format)
Definition: cnv.c:4548
#define CNV_ER_FMT_BAD_MSEC
Definition: cnverr.h:145
int db_timestamp_decode_ses(const DB_TIMESTAMP *utime, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:764
DB_BIGINT db_get_bigint(const DB_VALUE *value)
#define DB_DEFAULT_SCALE
Definition: dbtype_def.h:561
#define CNV_ER_FMT_BAD_THOUS
Definition: cnverr.h:91
#define CNV_ER_FMT_BAD_MONTH
Definition: cnverr.h:125
static const char * kr_long_month_names[]
Definition: cnv.c:428
const char * raw_text
Definition: cnvlex.h:114
int64_t DB_BIGINT
Definition: dbtype_def.h:751
FORMAT_DIGIT integral_type
Definition: cnv.c:177
int db_bit_string(const DB_VALUE *the_db_bit, const char *bit_format, char *string, int max_size)
Definition: cnv.c:8575
static ADJ_ARRAY * cnv_get_value_string_buffer(int nchars)
Definition: cnv.c:2632
#define CAST_BUFLEN
Definition: porting.h:471
static void error(const char *msg)
Definition: gencat.c:331
int db_make_float(DB_VALUE *value, const DB_C_FLOAT num)
#define DB_DEFAULT_PRECISION
Definition: dbtype_def.h:558
#define CNV_ER_FMT_BAD_TIMESTAMP
Definition: cnverr.h:149
#define CNV_ER_FMT_NO_DECIMAL
Definition: cnverr.h:83
#define CNV_ER_FMT_BAD_LEADING
Definition: cnverr.h:87
static const char * ffmt_value(FLOAT_FORMAT *ffmt, const char *string, double *the_double)
Definition: cnv.c:4625
static int fmt_second_value(const char *, int *)
Definition: cnv.c:4234
#define DB_BIGINT_MAX
Definition: dbtype_def.h:640
FORMAT_CURRENCY
Definition: cnv.c:151
static const char * local_thousands(void)
Definition: cnv.c:1699
const char * db_string_float(const char *float_string, const char *float_format, float *the_float)
Definition: cnv.c:7357
#define CNV_ERR_EXTRA_FRACTION
Definition: cnverr.h:41
#define DB_INT16_MAX
Definition: dbtype_def.h:630
unsigned int DB_TIME
Definition: dbtype_def.h:754
#define LOCAL_SLASH
Definition: cnv.c:115
unsigned int DB_DATE
Definition: dbtype_def.h:771
#define wcs_eql(ws1, ws2)
Definition: cnv.c:105
int length
Definition: cnvlex.h:113
#define DB_BIGINT_MIN
Definition: dbtype_def.h:641
const char * db_string_monetary(const char *monetary_string, const char *monetary_format, DB_MONETARY *the_monetary)
Definition: cnv.c:7572
static int ko_date_value(int *the_month, int *the_day, int *the_year)
Definition: cnv.c:1139
static int bin_string_to_int(const char *src, int nbits)
Definition: cnv.c:5772
void cnv_fmt_unlex()
Definition: cnvlex.c:1883
void numeric_coerce_dec_str_to_num(const char *dec_str, DB_C_NUMERIC result)
#define strlen(s1)
Definition: intl_support.c:43
int db_datetime_encode(DB_DATETIME *datetime, int month, int day, int year, int hour, int minute, int second, int millisecond)
Definition: db_date.c:4597
static const char * local_decimal(void)
Definition: cnv.c:1711
DB_DATE * db_get_date(const DB_VALUE *value)
#define HEX_IN_BYTE
Definition: cnv.c:63
const char * db_string_datetime(const char *datetime_string, const char *datetime_format, DB_DATETIME *the_datetime)
Definition: cnv.c:8273
#define FMT_Z()
Definition: cnv.c:123
FORMAT_DIGIT fractional_type
Definition: cnv.c:189
int intl_char_count(const unsigned char *src, int length_in_bytes, INTL_CODESET src_codeset, int *char_count)
Definition: intl_support.c:983
static int fmt_integral_digits(FORMAT_DIGIT digit_type, int ndigits, bool sign_required, bool thousands, double *the_value, int *nfound)
Definition: cnv.c:2772
static const char nbits[]
Definition: query_bitset.c:44
int adj_ar_insert(ADJ_ARRAY *adj_array_p, const void *src, int src_length, int start)
static int local_am_pm_value(bool *)
Definition: cnv.c:2177
FMT_TOKEN_TYPE
Definition: cnvlex.h:59
DB_TIMESTAMP * db_get_timestamp(const DB_VALUE *value)
DB_C_SHORT db_get_short(const DB_VALUE *value)
#define FMT_MAX_MTIME_STRING
Definition: cnv.c:94
static bool mfmt_valid_char(FMT_TOKEN *token)
Definition: cnv.c:4838
int db_make_varnchar(DB_VALUE *value, const int max_nchar_length, DB_CONST_C_NCHAR str, const int nchar_str_byte_size, const int codeset, const int collation_id)
FORMAT_CURRENCY format
Definition: cnv.c:190
#define CNV_ER_FMT_BAD_FORMAT
Definition: cnverr.h:162
#define TP_FLOATING_PRECISION_VALUE
#define FMT_STAR()
Definition: cnv.c:126
Definition: cnvlex.h:73
#define LOCAL_STAR
Definition: cnv.c:108
#define CNV_ER_FMT_BAD_YEAR
Definition: cnverr.h:123
DB_CURRENCY db_value_get_monetary_currency(const DB_VALUE *value)
Definition: db_macro.c:1492
#define DB_VALUE_TYPE(value)
Definition: dbtype.h:72
#define DB_CURRENCY_DEFAULT
Definition: dbtype.h:46
int i
Definition: dynamic_load.c:954
#define BITS_IN_HEX
Definition: cnv.c:64
Definition: cnvlex.h:84
#define CNV_ERR_BAD_TIME
Definition: cnverr.h:62
#define CNV_ERR_FLOAT_UNDERFLOW
Definition: cnverr.h:60
int db_make_double(DB_VALUE *value, const DB_C_DOUBLE num)
static const wchar_t * cnv_wcs(const char *mbs)
Definition: cnv.c:2356
#define CNV_ERR_TIMESTAMP_UNDERFLOW
Definition: cnverr.h:69
static const char * bfmt_value(BIT_STRING_FORMAT bfmt, const char *string, DB_VALUE *the_db_bit)
Definition: cnv.c:5819
#define FMT_CURRENCY()
Definition: cnv.c:128
void db_date_decode(const DB_DATE *date, int *monthp, int *dayp, int *yearp)
Definition: db_date.c:338
#define CNV_ERR_EXTRA_INTEGER
Definition: cnverr.h:40
DB_DATETIME * db_get_datetime(const DB_VALUE *value)
#define CNV_ERR_BAD_MIN
Definition: cnverr.h:64
#define FMT_DIGITS()
Definition: cnv.c:129
const char * db_string_numeric(const char *string, const char *numeric_format, DB_VALUE *the_numeric)
#define KOREAN_EUC_YEAR_SYMBOL
Definition: cnv.c:132
#define CNV_ER_FMT_BAD_SEC
Definition: cnverr.h:143
int db_make_timestamp(DB_VALUE *value, const DB_C_TIMESTAMP timeval)
int db_make_int(DB_VALUE *value, const int num)
#define FMT_9()
Definition: cnv.c:124
int DB_C_INT
Definition: dbtype_def.h:1149
static const char * eng_long_weekday_names[]
Definition: cnv.c:483
int db_make_char(DB_VALUE *value, const int char_length, DB_CONST_C_CHAR str, const int char_str_byte_size, const int codeset, const int collation_id)
#define CNV_ER_FMT_INTEGER_OVERFLOW
Definition: cnverr.h:109
#define LANG_SYS_CODESET
#define CNV_ER_FMT_MISSING_FRACTION
Definition: cnverr.h:99
#define FMT_THOUSANDS()
Definition: cnv.c:121
#define CNV_ER_FMT_BAD_NULL
Definition: cnverr.h:105
bool sign_required
Definition: cnv.c:161
DB_TIME * db_get_time(const DB_VALUE *value)
#define CNV_ERR_BAD_TRAILING
Definition: cnverr.h:38
void db_time_decode(DB_TIME *timeval, int *hourp, int *minutep, int *secondp)
Definition: db_date.c:432
#define DB_INT16_MIN
Definition: dbtype_def.h:629
#define CNV_ERR_BAD_MSEC
Definition: cnverr.h:66
#define CNV_ER_FMT_FLOAT_OVERFLOW
Definition: cnverr.h:131
#define CNV_ERR_BAD_DATE
Definition: cnverr.h:54
#define CNV_ERR_BAD_PATTERN
Definition: cnverr.h:50
int db_numeric_string(const DB_VALUE *the_numeric, const char *numeric_format, char *string, int max_size)
Definition: cnv.c:7317
ADJ_ARRAY * adj_ar_new(int element_size, int min, float growth_rate)
static int local_time_value(int *, int *, int *)
Definition: cnv.c:2128
static int fmt_timestamp_value(const char *descriptor, int *the_month, int *the_day, int *the_year, int *the_hour, int *the_min, int *the_sec)
Definition: cnv.c:4334
double amount
Definition: dbtype_def.h:831
static const char * local_time_string(const DB_TIME *the_time)
Definition: cnv.c:2090
#define CNV_ERR_BAD_HEX_DIGIT
Definition: cnv.c:78
int db_make_bit(DB_VALUE *value, const int bit_length, DB_CONST_C_BIT bit_str, const int bit_str_bit_size)
#define CNV_ER_FMT_BAD_AM_PM
Definition: cnverr.h:147
int db_string_to_date(const char *str, DB_DATE *date)
Definition: db_date.c:3693
static const char * eng_long_month_names[]
Definition: cnv.c:458
static const char * fmt_time_string(const DB_TIME *the_time, const char *descriptor)
Definition: cnv.c:3870
const char ** p
Definition: dynamic_load.c:945
#define CNV_ERR_INTEGER_UNDERFLOW
Definition: cnverr.h:49
#define CNV_ERR_UNKNOWN_DATE
Definition: cnverr.h:61
#define CNV_ERR_TIMESTAMP_OVERFLOW
Definition: cnverr.h:70
static const char * ko_time_string(const DB_TIME *the_time)
Definition: cnv.c:1335
static void bfmt_new(BIT_STRING_FORMAT *bfmt, const char *format)
Definition: cnv.c:5744
#define FMT_PLUS()
Definition: cnv.c:127
int db_make_nchar(DB_VALUE *value, const int nchar_length, DB_CONST_C_NCHAR str, const int nchar_str_byte_size, const int codeset, const int collation_id)
#define BITS_IN_BYTE
Definition: cnv.c:62
bit_string_format_e
Definition: cnv.c:195
static int bfmt_print(BIT_STRING_FORMAT *bfmt, const DB_VALUE *the_db_bit, char *string, int max_size)
Definition: cnv.c:5943
FORMAT_DIGIT fractional_type
Definition: cnv.c:168
int db_value_domain_init(DB_VALUE *value, const DB_TYPE type, const int precision, const int scale)
Definition: db_macro.c:153
#define CNV_ERR_BAD_TYPE
Definition: cnverr.h:33
void adj_ar_free(ADJ_ARRAY *adj_array_p)
static int fmt_date_value(const char *descriptor, int *the_month, int *the_day, int *the_year)
Definition: cnv.c:3594