1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
33 #include "dictionary.h"
35 #include "identifier.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/compiler.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/integer-format.h"
40 #include "libpspp/misc.h"
41 #include "libpspp/str.h"
45 #include "gl/c-ctype.h"
46 #include "gl/c-strtod.h"
47 #include "gl/minmax.h"
48 #include "gl/xalloc.h"
51 #define _(msgid) gettext (msgid)
53 /* Information about parsing one data field. */
56 struct substring input; /* Source. */
57 enum fmt_type format; /* Input format. */
59 union value *output; /* Destination. */
60 int width; /* Output width. */
63 typedef char *data_in_parser_func (struct data_in *);
64 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
65 static data_in_parser_func parse_##METHOD;
68 static void default_result (struct data_in *);
69 static bool trim_spaces_and_check_missing (struct data_in *);
71 static int hexit_value (int c);
73 /* Parses the characters in INPUT, which are encoded in the given
74 INPUT_ENCODING, according to FORMAT.
76 Stores the parsed representation in OUTPUT, which the caller must have
77 initialized with the given WIDTH (0 for a numeric field, otherwise the
78 string width). If FORMAT is FMT_A, then OUTPUT_ENCODING must specify the
79 correct encoding for OUTPUT (normally obtained via dict_get_encoding()).
81 If successful NULL is the return value. Otherwise a string describing
82 the problem is returned. The caller must free this string.
85 data_in (struct substring input, const char *input_encoding,
87 union value *output, int width, const char *output_encoding)
89 static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
91 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
97 enum fmt_category cat;
98 const char *dest_encoding;
102 assert ((width != 0) == fmt_is_string (format));
109 if (ss_is_empty (input))
115 cat = fmt_get_category (format);
116 if (cat & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL
117 | FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT))
119 /* We're going to parse these into numbers. For this purpose we want to
120 deal with them in the local "C" encoding. Any character not in that
121 encoding wouldn't be valid anyhow. */
122 dest_encoding = C_ENCODING;
124 else if (cat & (FMT_CAT_BINARY | FMT_CAT_LEGACY))
126 /* Don't recode these binary formats at all, since they are not text. */
127 dest_encoding = NULL;
131 assert (cat == FMT_CAT_STRING);
132 if (format == FMT_AHEX)
134 /* We want the hex digits in the local "C" encoding, even though the
135 result may not be in that encoding. */
136 dest_encoding = C_ENCODING;
140 /* Use the final output encoding. */
141 dest_encoding = output_encoding;
145 if (dest_encoding != NULL)
147 i.input = recode_substring_pool (dest_encoding, input_encoding, input,
157 error = handlers[i.format] (&i);
167 data_in_msg (struct substring input, const char *input_encoding,
168 enum fmt_type format,
169 union value *output, int width, const char *output_encoding)
171 char *error = data_in (input, input_encoding, format,
172 output, width, output_encoding);
175 msg (SW,_("Data is not valid as format %s: %s"),
176 fmt_name (format), error);
185 number_has_implied_decimals (const char *s, enum fmt_type type)
187 int decimal = settings_get_style (type)->decimal;
188 bool got_digit = false;
193 case '0': case '1': case '2': case '3': case '4':
194 case '5': case '6': case '7': case '8': case '9':
203 case 'e': case 'E': case 'd': case 'D':
223 has_implied_decimals (struct substring input, const char *input_encoding,
224 enum fmt_type format)
251 s = recode_string (C_ENCODING, input_encoding,
252 ss_data (input), ss_length (input));
253 retval = (format == FMT_Z
254 ? strchr (s, '.') == NULL
255 : number_has_implied_decimals (s, format));
261 /* In some cases, when no decimal point is explicitly included in numeric
262 input, its position is implied by the number of decimal places in the input
263 format. In such a case, this function may be called just after data_in().
264 Its arguments are a subset of that function's arguments plus D, the number
265 of decimal places associated with FORMAT.
267 If it is appropriate, this function modifies the numeric value in OUTPUT. */
269 data_in_imply_decimals (struct substring input, const char *input_encoding,
270 enum fmt_type format, int d, union value *output)
272 if (d > 0 && output->f != SYSMIS
273 && has_implied_decimals (input, input_encoding, format))
274 output->f /= pow (10., d);
277 /* Format parsers. */
279 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
281 parse_number (struct data_in *i)
283 const struct fmt_number_style *style =
284 settings_get_style (i->format);
291 if (fmt_get_category (i->format) == FMT_CAT_CUSTOM)
293 style = settings_get_style (FMT_F);
296 /* Trim spaces and check for missing value representation. */
297 if (trim_spaces_and_check_missing (i))
300 ds_init_empty (&tmp);
301 ds_extend (&tmp, 64);
303 /* Prefix character may precede sign. */
304 if (style->prefix.s[0] != '\0')
306 ss_match_byte (&i->input, style->prefix.s[0]);
307 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
311 if (ss_match_byte (&i->input, '-'))
313 ds_put_byte (&tmp, '-');
314 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
318 ss_match_byte (&i->input, '+');
319 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
322 /* Prefix character may follow sign. */
323 if (style->prefix.s[0] != '\0')
325 ss_match_byte (&i->input, style->prefix.s[0]);
326 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
329 /* Digits before decimal point. */
330 while (c_isdigit (ss_first (i->input)))
332 ds_put_byte (&tmp, ss_get_byte (&i->input));
333 if (style->grouping != 0)
334 ss_match_byte (&i->input, style->grouping);
337 /* Decimal point and following digits. */
338 if (ss_match_byte (&i->input, style->decimal))
340 ds_put_byte (&tmp, '.');
341 while (c_isdigit (ss_first (i->input)))
342 ds_put_byte (&tmp, ss_get_byte (&i->input));
346 if (!ds_is_empty (&tmp)
347 && !ss_is_empty (i->input)
348 && strchr ("eEdD-+", ss_first (i->input)))
350 ds_put_byte (&tmp, 'e');
352 if (strchr ("eEdD", ss_first (i->input)))
354 ss_advance (&i->input, 1);
355 ss_match_byte (&i->input, ' ');
358 if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
360 if (ss_get_byte (&i->input) == '-')
361 ds_put_byte (&tmp, '-');
362 ss_match_byte (&i->input, ' ');
365 while (c_isdigit (ss_first (i->input)))
366 ds_put_byte (&tmp, ss_get_byte (&i->input));
369 /* Suffix character. */
370 if (style->suffix.s[0] != '\0')
371 ss_match_byte (&i->input, style->suffix.s[0]);
373 if (!ss_is_empty (i->input))
376 if (ds_is_empty (&tmp))
377 error = xstrdup (_("Field contents are not numeric."));
379 error = xstrdup (_("Number followed by garbage."));
384 /* Let c_strtod() do the conversion. */
387 i->output->f = c_strtod (ds_cstr (&tmp), &tail);
392 return xstrdup (_("Invalid numeric syntax."));
394 else if (errno == ERANGE)
396 if (fabs (i->output->f) > 1)
398 i->output->f = SYSMIS;
400 return xstrdup (_("Too-large number set to system-missing."));
406 return xstrdup (_("Too-small number set to zero."));
416 /* Parses N format. */
418 parse_N (struct data_in *i)
423 while ((c = ss_get_byte (&i->input)) != EOF)
426 return xstrdup (_("All characters in field must be digits."));
427 i->output->f = i->output->f * 10.0 + (c - '0');
433 /* Parses PIBHEX format. */
435 parse_PIBHEX (struct data_in *i)
442 while ((c = ss_get_byte (&i->input)) != EOF)
445 return xstrdup (_("Unrecognized character in field."));
446 n = n * 16.0 + hexit_value (c);
453 /* Parses RBHEX format. */
455 parse_RBHEX (struct data_in *i)
460 memset (&d, 0, sizeof d);
461 for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
463 int hi = ss_get_byte (&i->input);
464 int lo = ss_get_byte (&i->input);
466 return xstrdup (_("Field must have even length."));
467 else if (!c_isxdigit (hi) || !c_isxdigit (lo))
468 return xstrdup (_("Field must contain only hex digits."));
469 ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
477 /* Digits for Z format. */
478 static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
480 /* Returns true if C is a Z format digit, false otherwise. */
484 return c > 0 && strchr (z_digits, c) != NULL;
487 /* Returns the (absolute value of the) value of C as a Z format
490 z_digit_value (int c)
492 assert (is_z_digit (c));
493 return (strchr (z_digits, c) - z_digits) % 10;
496 /* Returns true if Z format digit C represents a negative value,
499 is_negative_z_digit (int c)
501 assert (is_z_digit (c));
502 return (strchr (z_digits, c) - z_digits) >= 20;
505 /* Parses Z format. */
507 parse_Z (struct data_in *i)
513 bool got_dot = false;
514 bool got_final_digit = false;
516 /* Trim spaces and check for missing value representation. */
517 if (trim_spaces_and_check_missing (i))
520 ds_init_empty (&tmp);
521 ds_extend (&tmp, 64);
523 ds_put_byte (&tmp, '+');
524 while (!ss_is_empty (i->input))
526 int c = ss_get_byte (&i->input);
527 if (c_isdigit (c) && !got_final_digit)
528 ds_put_byte (&tmp, c);
529 else if (is_z_digit (c) && !got_final_digit)
531 ds_put_byte (&tmp, z_digit_value (c) + '0');
532 if (is_negative_z_digit (c))
533 ds_data (&tmp)[0] = '-';
534 got_final_digit = true;
536 else if (c == '.' && !got_dot)
538 ds_put_byte (&tmp, '.');
544 return xstrdup (_("Invalid zoned decimal syntax."));
548 if (!ss_is_empty (i->input))
552 if (ds_length (&tmp) == 1)
553 error = xstrdup (_("Field contents are not numeric."));
555 error = xstrdup (_("Number followed by garbage."));
561 /* Let c_strtod() do the conversion. */
564 i->output->f = c_strtod (ds_cstr (&tmp), NULL);
567 if (fabs (i->output->f) > 1)
569 i->output->f = SYSMIS;
571 return xstrdup (_("Too-large number set to system-missing."));
577 return xstrdup (_("Too-small number set to zero."));
587 /* Parses IB format. */
589 parse_IB (struct data_in *i)
595 bytes = MIN (8, ss_length (i->input));
596 value = integer_get (settings_get_input_integer_format (), ss_data (i->input), bytes);
598 sign_bit = UINT64_C(1) << (8 * bytes - 1);
599 if (!(value & sign_bit))
600 i->output->f = value;
603 /* Sign-extend to full 64 bits. */
604 value -= sign_bit << 1;
605 i->output->f = -(double) -value;
611 /* Parses PIB format. */
613 parse_PIB (struct data_in *i)
615 i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
616 MIN (8, ss_length (i->input)));
621 /* Consumes the first character of S. Stores its high 4 bits in
622 HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
624 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
626 int c = ss_get_byte (s);
628 *high_nibble = (c >> 4) & 15;
629 *low_nibble = c & 15;
632 /* Parses P format. */
634 parse_P (struct data_in *i)
636 int high_nibble, low_nibble;
640 while (ss_length (i->input) > 1)
642 get_nibbles (&i->input, &high_nibble, &low_nibble);
643 if (high_nibble > 9 || low_nibble > 9)
644 return xstrdup (_("Invalid syntax for P field."));
645 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
648 get_nibbles (&i->input, &high_nibble, &low_nibble);
650 return xstrdup (_("Invalid syntax for P field."));
651 i->output->f = (10 * i->output->f) + high_nibble;
653 i->output->f = (10 * i->output->f) + low_nibble;
654 else if (low_nibble == 0xb || low_nibble == 0xd)
655 i->output->f = -i->output->f;
660 /* Parses PK format. */
662 parse_PK (struct data_in *i)
665 while (!ss_is_empty (i->input))
667 int high_nibble, low_nibble;
669 get_nibbles (&i->input, &high_nibble, &low_nibble);
670 if (high_nibble > 9 || low_nibble > 9)
672 i->output->f = SYSMIS;
675 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
681 /* Parses RB format. */
683 parse_RB (struct data_in *i)
685 enum float_format ff = settings_get_input_float_format ();
686 size_t size = float_get_size (ff);
687 if (ss_length (i->input) >= size)
688 float_convert (ff, ss_data (i->input),
689 FLOAT_NATIVE_DOUBLE, &i->output->f);
691 i->output->f = SYSMIS;
696 /* Parses A format. */
698 parse_A (struct data_in *i)
700 /* This is equivalent to buf_copy_rpad, except that we posibly
701 do a character set recoding in the middle. */
702 uint8_t *dst = value_str_rw (i->output, i->width);
703 size_t dst_size = i->width;
704 const char *src = ss_data (i->input);
705 size_t src_size = ss_length (i->input);
707 memcpy (dst, src, MIN (src_size, dst_size));
709 if (dst_size > src_size)
710 memset (&dst[src_size], ' ', dst_size - src_size);
715 /* Parses AHEX format. */
717 parse_AHEX (struct data_in *i)
719 uint8_t *s = value_str_rw (i->output, i->width);
724 int hi = ss_get_byte (&i->input);
725 int lo = ss_get_byte (&i->input);
729 return xstrdup (_("Field must have even length."));
731 if (!c_isxdigit (hi) || !c_isxdigit (lo))
732 return xstrdup (_("Field must contain only hex digits."));
735 s[j] = hexit_value (hi) * 16 + hexit_value (lo);
738 memset (&s[j], ' ', i->width - j);
743 /* Date & time format components. */
745 /* Sign of a time value. */
748 SIGN_NO_TIME, /* No time yet encountered. */
749 SIGN_POSITIVE, /* Positive time. */
750 SIGN_NEGATIVE /* Negative time. */
753 /* Parses a signed decimal integer from at most the first
754 MAX_DIGITS characters in I, storing the result into *RESULT.
755 Returns true if successful, false if no integer was
757 static char * WARN_UNUSED_RESULT
758 parse_int (struct data_in *i, long *result, size_t max_digits)
760 struct substring head = ss_head (i->input, max_digits);
761 size_t n = ss_get_long (&head, result);
764 ss_advance (&i->input, n);
768 return xstrdup (_("Syntax error in date field."));
771 /* Parses a date integer between 1 and 31 from I, storing it into
773 Returns true if successful, false if no date was present. */
775 parse_day (struct data_in *i, long *day)
777 char *error = parse_int (i, day, SIZE_MAX);
780 if (*day >= 1 && *day <= 31)
783 return xasprintf (_("Day (%ld) must be between 1 and 31."), *day);
786 /* Parses an integer from the beginning of I.
787 Adds SECONDS_PER_UNIT times the absolute value of the integer
789 If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
790 time and sets *TIME_SIGN. Otherwise, does not allow a sign.
791 Returns true if successful, false if no integer was present. */
793 parse_time_units (struct data_in *i, double seconds_per_unit,
794 enum time_sign *time_sign, double *time)
800 if (*time_sign == SIGN_NO_TIME)
802 if (ss_match_byte (&i->input, '-'))
803 *time_sign = SIGN_NEGATIVE;
806 ss_match_byte (&i->input, '+');
807 *time_sign = SIGN_POSITIVE;
810 error = parse_int (i, &units, SIZE_MAX);
814 return xstrdup (_("Syntax error in date field."));
815 *time += units * seconds_per_unit;
819 /* Parses a data delimiter from the beginning of I.
820 Returns true if successful, false if no delimiter was
823 parse_date_delimiter (struct data_in *i)
825 if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
828 return xstrdup (_("Delimiter expected between fields in date."));
831 /* Parses spaces at the beginning of I. */
833 parse_spaces (struct data_in *i)
835 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
838 static struct substring
839 parse_name_token (struct data_in *i)
841 struct substring token;
842 ss_get_bytes (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
846 /* Reads a name from I and sets *OUTPUT to the value associated
847 with that name. If ALLOW_SUFFIXES is true, then names that
848 begin with one of the names are accepted; otherwise, only
849 exact matches (except for case) are allowed.
850 Returns true if successful, false otherwise. */
852 match_name (struct substring token, const char *const *names, long *output)
856 for (i = 1; *names != NULL; i++)
857 if (ss_equals_case (ss_cstr (*names++), token))
866 /* Parses a month name or number from the beginning of I,
867 storing the month (in range 1...12) into *MONTH.
868 Returns true if successful, false if no month was present. */
870 parse_month (struct data_in *i, long *month)
872 if (c_isdigit (ss_first (i->input)))
874 char *error = parse_int (i, month, SIZE_MAX);
877 if (*month >= 1 && *month <= 12)
882 static const char *const english_names[] =
884 "jan", "feb", "mar", "apr", "may", "jun",
885 "jul", "aug", "sep", "oct", "nov", "dec",
889 static const char *const roman_names[] =
891 "i", "ii", "iii", "iv", "v", "vi",
892 "vii", "viii", "ix", "x", "xi", "xii",
896 struct substring token = parse_name_token (i);
897 if (match_name (ss_head (token, 3), english_names, month)
898 || match_name (ss_head (token, 4), roman_names, month))
902 return xstrdup (_("Unrecognized month format. Months may be specified "
903 "as Arabic or Roman numerals or as at least 3 letters "
904 "of their English names."));
907 /* Parses a year of at most MAX_DIGITS from the beginning of I,
908 storing a "4-digit" year into *YEAR. */
910 parse_year (struct data_in *i, long *year, size_t max_digits)
912 char *error = parse_int (i, year, max_digits);
916 if (*year >= 0 && *year <= 99)
918 int epoch = settings_get_epoch ();
919 int epoch_century = ROUND_DOWN (epoch, 100);
920 int epoch_offset = epoch - epoch_century;
921 if (*year >= epoch_offset)
922 *year += epoch_century;
924 *year += epoch_century + 100;
926 if (*year >= 1582 && *year <= 19999)
929 return xasprintf (_("Year (%ld) must be between 1582 and 19999."), *year);
932 /* Returns true if input in I has been exhausted,
935 parse_trailer (struct data_in *i)
937 if (ss_is_empty (i->input))
940 return xasprintf (_("Trailing garbage `%.*s' following date."),
941 (int) ss_length (i->input), ss_data (i->input));
944 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
945 Returns true if successful, false on failure. */
947 parse_yday (struct data_in *i, long *yday)
949 struct substring num_s;
952 ss_get_bytes (&i->input, 3, &num_s);
953 if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
954 return xstrdup (_("Julian day must have exactly three digits."));
955 else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
956 return xasprintf (_("Julian day (%ld) must be between 1 and 366."), num);
962 /* Parses a quarter-of-year integer between 1 and 4 from I.
963 Stores the corresponding month into *MONTH.
964 Returns true if successful, false if no quarter was present. */
966 parse_quarter (struct data_in *i, long int *month)
971 error = parse_int (i, &quarter, SIZE_MAX);
974 if (quarter >= 1 && quarter <= 4)
976 *month = (quarter - 1) * 3 + 1;
980 return xasprintf (_("Quarter (%ld) must be between 1 and 4."), quarter);
983 /* Parses a week-of-year integer between 1 and 53 from I,
984 Stores the corresponding year-of-day into *YDAY.
985 Returns true if successful, false if no week was present. */
987 parse_week (struct data_in *i, long int *yday)
992 error = parse_int (i, &week, SIZE_MAX);
995 if (week >= 1 && week <= 53)
997 *yday = (week - 1) * 7 + 1;
1001 return xasprintf (_("Week (%ld) must be between 1 and 53."), week);
1004 /* Parses a time delimiter from the beginning of I.
1005 Returns true if successful, false if no delimiter was
1008 parse_time_delimiter (struct data_in *i)
1010 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
1013 return xstrdup (_("Delimiter expected between fields in time."));
1016 /* Parses minutes and optional seconds from the beginning of I.
1017 The time is converted into seconds, which are added to
1019 Returns true if successful, false if an error was found. */
1021 parse_minute_second (struct data_in *i, double *time)
1028 /* Parse minutes. */
1029 error = parse_int (i, &minute, SIZE_MAX);
1032 if (minute < 0 || minute > 59)
1033 return xasprintf (_("Minute (%ld) must be between 0 and 59."), minute);
1034 *time += 60. * minute;
1036 /* Check for seconds. */
1037 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
1038 || !c_isdigit (ss_first (i->input)))
1041 /* Parse seconds. */
1043 while (c_isdigit (ss_first (i->input)))
1044 *cp++ = ss_get_byte (&i->input);
1045 if (ss_match_byte (&i->input, settings_get_decimal_char (FMT_F)))
1047 while (c_isdigit (ss_first (i->input)))
1048 *cp++ = ss_get_byte (&i->input);
1051 *time += c_strtod (buf, NULL);
1056 /* Parses a weekday name from the beginning of I,
1057 storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
1058 Returns true if successful, false if an error was found. */
1060 parse_weekday (struct data_in *i, long *weekday)
1062 static const char *const weekday_names[] =
1064 "su", "mo", "tu", "we", "th", "fr", "sa",
1068 struct substring token = parse_name_token (i);
1069 bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
1071 return xstrdup (_("Unrecognized weekday name. At least the first two "
1072 "letters of an English weekday name must be "
1077 /* Date & time formats. */
1079 /* Parses WKDAY format. */
1081 parse_WKDAY (struct data_in *i)
1086 if (trim_spaces_and_check_missing (i))
1089 error = parse_weekday (i, &weekday);
1091 error = parse_trailer (i);
1093 i->output->f = weekday;
1097 /* Parses MONTH format. */
1099 parse_MONTH (struct data_in *i)
1104 if (trim_spaces_and_check_missing (i))
1107 error = parse_month (i, &month);
1109 error = parse_trailer (i);
1111 i->output->f = month;
1115 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
1116 DATETIME, TIME and DTIME formats. */
1118 parse_date (struct data_in *i)
1120 long int year = INT_MIN;
1124 double time = 0, date = 0;
1125 enum time_sign time_sign = SIGN_NO_TIME;
1127 const char *template = fmt_date_template (i->format, 0);
1128 size_t template_width = strlen (template);
1131 if (trim_spaces_and_check_missing (i))
1134 while (*template != '\0')
1136 unsigned char ch = *template;
1139 while (template[count] == ch)
1146 error = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
1149 error = parse_month (i, &month);
1154 if (!c_isalpha (*template))
1155 max_digits = SIZE_MAX;
1158 if (ss_length (i->input) >= template_width + 2)
1163 error = parse_year (i, &year, max_digits);
1167 error = parse_quarter (i, &month);
1170 error = parse_week (i, &yday);
1173 error = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
1176 error = parse_time_units (i, 60. * 60., &time_sign, &time);
1179 error = parse_minute_second (i, &time);
1184 error = parse_date_delimiter (i);
1187 error = parse_time_delimiter (i);
1189 if (i->format != FMT_MOYR)
1195 error = parse_date_delimiter (i);
1198 assert (count == 1);
1199 if (!ss_match_byte (&i->input, c_toupper (ch))
1200 && !ss_match_byte (&i->input, c_tolower (ch)))
1201 error = xasprintf (_("`%c' expected in date field."), ch);
1209 error = parse_trailer (i);
1213 if (year != INT_MIN)
1218 ofs = calendar_gregorian_to_offset (year, month, day, &error);
1221 date = (yday - 1 + ofs) * 60. * 60. * 24.;
1225 i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
1230 /* Utility functions. */
1232 /* Sets the default result for I.
1233 For a numeric format, this is the value set on SET BLANKS
1234 (typically system-missing); for a string format, it is all
1237 default_result (struct data_in *i)
1239 if (fmt_is_string (i->format))
1240 memset (value_str_rw (i->output, i->width), ' ', i->width);
1242 i->output->f = settings_get_blanks ();
1245 /* Trims leading and trailing spaces from I.
1246 If the result is empty, or a single period character, then
1247 sets the default result and returns true; otherwise, returns
1250 trim_spaces_and_check_missing (struct data_in *i)
1252 ss_trim (&i->input, ss_cstr (" "));
1253 if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))
1261 /* Returns the integer value of hex digit C. */
1265 const char s[] = "0123456789abcdef";
1266 const char *cp = strchr (s, c_tolower ((unsigned char) c));
1268 assert (cp != NULL);